diff options
author | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
commit | 663d5a0f32ed8dfc091ffb6153161591ac6ba563 (patch) | |
tree | 60b090a6cbdb64326bb128ea49a231d08eb2680e /contrib/amd/doc | |
download | FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.zip FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.tar.gz |
Virgin import of AMD (am-utils) v6.0a16
Diffstat (limited to 'contrib/amd/doc')
-rw-r--r-- | contrib/amd/doc/am-utils.texi | 7816 | ||||
-rw-r--r-- | contrib/amd/doc/stamp-vti | 3 | ||||
-rw-r--r-- | contrib/amd/doc/texinfo.tex | 4935 | ||||
-rw-r--r-- | contrib/amd/doc/version.texi | 3 |
4 files changed, 12757 insertions, 0 deletions
diff --git a/contrib/amd/doc/am-utils.texi b/contrib/amd/doc/am-utils.texi new file mode 100644 index 0000000..ca54503 --- /dev/null +++ b/contrib/amd/doc/am-utils.texi @@ -0,0 +1,7816 @@ +\input texinfo @c -*-texinfo-*- +@c +@c Copyright (c) 1997-1998 Erez Zadok +@c Copyright (c) 1989 Jan-Simon Pendry +@c Copyright (c) 1989 Imperial College of Science, Technology & Medicine +@c Copyright (c) 1989 The Regents of the University of California. +@c All rights reserved. +@c +@c This code is derived from software contributed to Berkeley by +@c Jan-Simon Pendry at Imperial College, London. +@c +@c Redistribution and use in source and binary forms, with or without +@c modification, are permitted provided that the following conditions +@c are met: +@c 1. Redistributions of source code must retain the above copyright +@c notice, this list of conditions and the following disclaimer. +@c 2. Redistributions in binary form must reproduce the above copyright +@c notice, this list of conditions and the following disclaimer in the +@c documentation and/or other materials provided with the distribution. +@c 3. All advertising materials mentioning features or use of this software +@c must display the following acknowledgment: +@c This product includes software developed by the University of +@c California, Berkeley and its contributors. +@c 4. Neither the name of the University nor the names of its contributors +@c may be used to endorse or promote products derived from this software +@c without specific prior written permission. +@c +@c THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +@c ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +@c IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +@c ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +@c FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +@c DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +@c OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +@c HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +@c LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +@c OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +@c +@c %W% (Berkeley) %G% +@c +@c $Id: am-utils.texi,v 6.0 1997/02/09 15:11:50 ezk beta $ +@c +@setfilename am-utils.info + +@include version.texi + +@c info directory entry +@direntry +* Am-utils: (am-utils). The Amd automounter suite of utilities +@end direntry + +@titlepage +@title Am-utils (4.4BSD Automounter Utilities) +@subtitle For version @value{VERSION}, @value{UPDATED} + +@author Erez Zadok +(Originally by Jan-Simon Pendry and Nick Williams) + +@page +Copyright @copyright{} 1997-1998 Erez Zadok +@* +Copyright @copyright{} 1989 Jan-Simon Pendry +@* +Copyright @copyright{} 1989 Imperial College of Science, Technology & Medicine +@* +Copyright @copyright{} 1989 The Regents of the University of California. +@sp +All Rights Reserved. +@vskip 1ex +Permission to copy this document, or any portion of it, as +necessary for use of this software is granted provided this +copyright notice and statement of permission are included. +@end titlepage +@page + +@c Define a new index for options. +@syncodeindex pg cp +@syncodeindex vr cp + +@ifinfo + +@c ################################################################ +@node Top, License, , (DIR) +Am-utils - The 4.4BSD Automounter Tool Suite +********************************************* + +Am-utils is the 4.4BSD Automounter Tool Suite, which includes the Amd +automounter, the Amq query and control program, the Hlfsd daemon, and +other tools. This Info file describes how to use and understand the +tools within Am-utils. +@end ifinfo + +@menu +* License:: Explains the terms and conditions for using + and distributing Am-utils. +* Distrib:: How to get the latest Am-utils distribution. +* Intro:: An introduction to Automounting concepts. +* History:: History of am-utils' development. +* Overview:: An overview of Amd. +* Supported Platforms:: Machines and Systems supported by Amd. +* Mount Maps:: Details of mount maps +* Amd Command Line Options:: All the Amd command line options explained. +* Filesystem Types:: The different mount types supported by Amd. +* Amd Configuration File:: The amd.conf file syntax and meaning. +* Run-time Administration:: How to start, stop and control Amd. +* FSinfo:: The FSinfo filesystem management tool. +* Hlfsd:: The Home-Link Filesystem server. +* Assorted Tools:: Other tools which come with am-utils. +* Examples:: Some examples showing how Amd might be used. +* Internals:: Implementation details. +* Acknowledgments & Trademarks:: Legal Notes + +Indexes +* Index:: An item for each concept. +@end menu + +@iftex +@unnumbered Preface + +This manual documents the use of the 4.4BSD automounter tool suite, +which includes @i{Amd}, @i{Amq}, @i{Hlfsd}, and other programs. This is +primarily a reference manual. While no tutorial exists, there are +examples available. @xref{Examples}. + +This manual comes in two forms: the published form and the Info form. +The Info form is for on-line perusal with the INFO program which is +distributed along with GNU texinfo package (a version of which is +available for GNU Emacs).@footnote{GNU packages can be found in +@url{ftp://ftp.gnu.org/pub/gnu/}.} Both forms contain substantially +the same text and are generated from a common source file, which is +distributed with the @i{Am-utils} source. +@end iftex + +@c ################################################################ +@node License, Distrib, Top, Top +@unnumbered License +@cindex License Information + +@i{Am-utils} is not in the public domain; it is copyrighted and there are +restrictions on its distribution. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +@enumerate + +@item +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +@item +Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +@item +All advertising materials mentioning features or use of this software +must display the following acknowledgment: + +@cartouche +``This product includes software developed by the University of +California, Berkeley and its contributors, as well as the Trustees of +Columbia University.'' +@end cartouche + +@item +Neither the name of the University nor the names of its contributors may +be used to endorse or promote products derived from this software +without specific prior written permission. + +@end enumerate + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. + +@c ################################################################ +@node Distrib, Intro, License, Top +@unnumbered Source Distribution +@cindex Source code distribution +@cindex Obtaining the source code + +The @i{Am-utils} home page is located in +@example +@url{http://www.cs.columbia.edu/~ezk/am-utils/} +@end example + +You can get the latest distribution version of @i{Am-utils} from +@example +@url{ftp://shekel.mcl.cs.columbia.edu/pub/am-utils/am-utils.tar.gz} +@end example + +Alpha and beta distributions are available in +@example +@url{ftp://shekel.mcl.cs.columbia.edu/pub/am-utils/}. +@end example + +Revision 5.2 was part of the 4.3BSD Reno distribution. + +Revision 5.3bsdnet, a late alpha version of 5.3, was part +of the BSD network version 2 distribution + +Revision 6.0 was made independently by @email{ezk@@cs.columbia.edu,Erez +Zadok} at the @uref{http://www.cs.columbia.edu/,Computer Science +Department} of @uref{http://www.columbia.edu/,Columbia University}, as +part of his @uref{http://www.cs.columbia.edu/~ezk/research/tp/thesis_proposal.html,PhD thesis work}. @xref{History} for more details. + +@unnumberedsec Bug Reports +@cindex Bug reports + +Before reporting a bug, see if it is a known one in the +@uref{http://www.cs.columbia.edu/~ezk/am-utils/BUGS.txt,bugs} file. +Send all bug reports to @email{amd-dev@@majordomo.cs.columbia.edu} +quoting the details of the release and your configuration. These can be +obtained by running the command @samp{amd -v}. It would greatly help if +you could provide a reproducible procedure for detecting the bug you are +reporting. + +Providing working patches is highly encouraged. Every patch +incorporated, however small, will get its author an honorable mention in +the @uref{http://www.cs.columbia.edu/~ezk/am-utils/AUTHORS.txt,authors +file}. + +@unnumberedsec Mailing List +@cindex Mailing list + +There are two mailing lists for people interested in keeping up-to-date +with developments. + +@c ############### + +@enumerate + +@item +The older list, @samp{amd-workers} is for general "how to" questions and +announcements. To subscribe, send a note to +@email{amd-workers-request@@majordomo.glue.umd.edu}.@footnote{Note that +the older address, @email{amd-workers-request@@acl.lanl.gov}, is +defunct.} To post a message to this list, send mail to +@email{amd-workers@@majordomo.glue.umd.edu}. + +@item +The developers only list, @samp{amd-dev} is for + +@itemize @minus +@item +announcements of alpha and beta releases of am-utils +@item +reporting of bugs and patches +@item +discussions of new features for am-utils +@item +implementation and porting issues +@end itemize + +To subscribe, send a note to @email{majordomo@@majordomo.cs.columbia.edu} +with the single body text line @samp{subscribe amd-dev}. To post a +message to this list, send mail to +@email{amd-dev@@majordomo.cs.columbia.edu}. To avoid as much spam as +possible, only subscribers to this list may post to it. + +Subscribers of @samp{amd-dev} are most suitable if they have the time +and resources to test new and buggy versions of amd, on as many +different platforms as possible. They should also be prepared to learn +and use the GNU Autoconf, Automake, and Libtool packages, and of course, +be very familiar with the complex code in the am-utils package. In +other words, subscribers on this list should be able to contribute +meaningfully to the development of amd. + +@end enumerate + +@c ################################################################ +@node Intro, History, Distrib, Top +@unnumbered Introduction +@cindex Introduction + +An @dfn{automounter} maintains a cache of mounted filesystems. +Filesystems are mounted on demand when they are first referenced, +and unmounted after a period of inactivity. + +@i{Amd} may be used as a replacement for Sun's automounter. The choice +of which filesystem to mount can be controlled dynamically with +@dfn{selectors}. Selectors allow decisions of the form ``hostname is +@var{this},'' or ``architecture is not @var{that}.'' Selectors may be +combined arbitrarily. @i{Amd} also supports a variety of filesystem +types, including NFS, UFS and the novel @dfn{program} filesystem. The +combination of selectors and multiple filesystem types allows identical +configuration files to be used on all machines thus reducing the +administrative overhead. + +@i{Amd} ensures that it will not hang if a remote server goes down. +Moreover, @i{Amd} can determine when a remote server has become +inaccessible and then mount replacement filesystems as and when they +become available. + +@i{Amd} contains no proprietary source code and has been ported to +numerous flavors of Unix. + +@c ################################################################ +@node History, Overview, Intro, Top +@unnumbered History +@cindex History + +The @i{Amd} package has been without an official maintainer since 1992. +Several people have stepped in to maintain it unofficially. Most +notable were the `upl' (Unofficial Patch Level) releases of @i{Amd}, +created by me (@email{ezk@@cs.columbia.edu,Erez Zadok}), and available from +@url{ftp://ftp.cs.columbia.edu/pub/amd/}. The last such unofficial +release was `upl102'. + +Through the process of patching and aging, it was becoming more and more +apparent that @i{Amd} was in much need of revitalizing. Maintaining +@i{Amd} had become a difficult task. I took it upon myself to cleanup +the code, so that it would be easier to port to new platforms, add new +features, keep up with the many new feature requests, and deal with the +never ending stream of bug reports. + +I have been working on such a release of @i{Amd} on and off since +January of 1996. The new suite of tools is currently named "am-utils" +(AutoMounter Utilities), in line with GNU naming conventions, befitting +the contents of the package. In October of 1996 I had received enough +offers to help me with this task that I decided to make a mailing list +for this group of people. Around the same time, @i{Amd} had become a +necessary part of my PhD thesis work, resulting in more work performed +on am-utils. + +Am-utils version 6.0 was numbered with a major new release number to +distinguish it from the last official release of @i{Amd} (5.x). Many +new features have been added such as a GNU @code{configure} system, NFS +Version 3, Autofs support, a run-time configuration file (`amd.conf'), +many new ports, more scripts and programs, as well as numerous bug +fixes. Another reason for the new major release number was to alert +users of am-utils that user-visible interfaces may have changed. In +order to make @i{Amd} work well for the next 10 years, and be easier to +maintain, it was necessary to remove old or unused features, change +various syntax files, etc. However, great care was taken to ensure the +maximum possible backwards compatibility. + +@c ################################################################ +@node Overview, Supported Platforms, History, Top +@chapter Overview + +@i{Amd} maintains a cache of mounted filesystems. Filesystems are +@dfn{demand-mounted} when they are first referenced, and unmounted after +a period of inactivity. @i{Amd} may be used as a replacement for Sun's +@b{automount}(8) program. It contains no proprietary source code and +has been ported to numerous flavors of Unix. @xref{Supported +Platforms}.@refill + +@i{Amd} was designed as the basis for experimenting with filesystem +layout and management. Although @i{Amd} has many direct applications it +is loaded with additional features which have little practical use. At +some point the infrequently used components may be removed to streamline +the production system. + +@c @i{Amd} supports the notion of @dfn{replicated} filesystems by evaluating +@c each member of a list of possible filesystem locations in parallel. +@c @i{Amd} checks that each cached mapping remains valid. Should a mapping be +@c lost -- such as happens when a fileserver goes down -- @i{Amd} automatically +@c selects a replacement should one be available. +@c +@menu +* Fundamentals:: +* Filesystems and Volumes:: +* Volume Naming:: +* Volume Binding:: +* Operational Principles:: +* Mounting a Volume:: +* Automatic Unmounting:: +* Keep-alives:: +* Non-blocking Operation:: +@end menu + +@node Fundamentals, Filesystems and Volumes, Overview, Overview +@comment node-name, next, previous, up +@section Fundamentals +@cindex Automounter fundamentals + +The fundamental concept behind @i{Amd} is the ability to separate the +name used to refer to a file from the name used to refer to its physical +storage location. This allows the same files to be accessed with the +same name regardless of where in the network the name is used. This is +very different from placing @file{/n/hostname} in front of the pathname +since that includes location dependent information which may change if +files are moved to another machine. + +By placing the required mappings in a centrally administered database, +filesystems can be re-organized without requiring changes to +configuration files, shell scripts and so on. + +@node Filesystems and Volumes, Volume Naming, Fundamentals, Overview +@comment node-name, next, previous, up +@section Filesystems and Volumes +@cindex Filesystem +@cindex Volume +@cindex Fileserver +@cindex sublink + +@i{Amd} views the world as a set of fileservers, each containing one or +more filesystems where each filesystem contains one or more +@dfn{volumes}. Here the term @dfn{volume} is used to refer to a +coherent set of files such as a user's home directory or a @TeX{} +distribution.@refill + +In order to access the contents of a volume, @i{Amd} must be told in +which filesystem the volume resides and which host owns the filesystem. +By default the host is assumed to be local and the volume is assumed to +be the entire filesystem. If a filesystem contains more than one +volume, then a @dfn{sublink} is used to refer to the sub-directory +within the filesystem where the volume can be found. + +@node Volume Naming, Volume Binding, Filesystems and Volumes, Overview +@comment node-name, next, previous, up +@section Volume Naming +@cindex Volume names +@cindex Network-wide naming +@cindex Replicated volumes +@cindex Duplicated volumes +@cindex Replacement volumes + +Volume names are defined to be unique across the entire network. A +volume name is the pathname to the volume's root as known by the users +of that volume. Since this name uniquely identifies the volume +contents, all volumes can be named and accessed from each host, subject +to administrative controls. + +Volumes may be replicated or duplicated. Replicated volumes contain +identical copies of the same data and reside at two or more locations in +the network. Each of the replicated volumes can be used +interchangeably. Duplicated volumes each have the same name but contain +different, though functionally identical, data. For example, +@samp{/vol/tex} might be the name of a @TeX{} distribution which varied +for each machine architecture.@refill + +@i{Amd} provides facilities to take advantage of both replicated and +duplicated volumes. Configuration options allow a single set of +configuration data to be shared across an entire network by taking +advantage of replicated and duplicated volumes. + +@i{Amd} can take advantage of replacement volumes by mounting them as +required should an active fileserver become unavailable. + +@node Volume Binding, Operational Principles, Volume Naming, Overview +@comment node-name, next, previous, up +@section Volume Binding +@cindex Volume binding +@cindex Unix namespace +@cindex Namespace +@cindex Binding names to filesystems + +Unix implements a namespace of hierarchically mounted filesystems. Two +forms of binding between names and files are provided. A @dfn{hard +link} completes the binding when the name is added to the filesystem. A +@dfn{soft link} delays the binding until the name is accessed. An +@dfn{automounter} adds a further form in which the binding of name to +filesystem is delayed until the name is accessed.@refill + +The target volume, in its general form, is a tuple (host, filesystem, +sublink) which can be used to name the physical location of any volume +in the network. + +When a target is referenced, @i{Amd} ignores the sublink element and +determines whether the required filesystem is already mounted. This is +done by computing the local mount point for the filesystem and checking +for an existing filesystem mounted at the same place. If such a +filesystem already exists then it is assumed to be functionally +identical to the target filesystem. By default there is a one-to-one +mapping between the pair (host, filesystem) and the local mount point so +this assumption is valid. + +@node Operational Principles, Mounting a Volume, Volume Binding, Overview +@comment node-name, next, previous, up +@section Operational Principles +@cindex Operational principles + +@i{Amd} operates by introducing new mount points into the namespace. +These are called @dfn{automount} points. The kernel sees these +automount points as NFS filesystems being served by @i{Amd}. Having +attached itself to the namespace, @i{Amd} is now able to control the +view the rest of the system has of those mount points. RPC calls are +received from the kernel one at a time. + +When a @dfn{lookup} call is received @i{Amd} checks whether the name is +already known. If it is not, the required volume is mounted. A +symbolic link pointing to the volume root is then returned. Once the +symbolic link is returned, the kernel will send all other requests +direct to the mounted filesystem. + +If a volume is not yet mounted, @i{Amd} consults a configuration +@dfn{mount-map} corresponding to the automount point. @i{Amd} then +makes a runtime decision on what and where to mount a filesystem based +on the information obtained from the map. + +@i{Amd} does not implement all the NFS requests; only those relevant +to name binding such as @dfn{lookup}, @dfn{readlink} and @dfn{readdir}. +Some other calls are also implemented but most simply return an error +code; for example @dfn{mkdir} always returns ``read-only filesystem''. + +@node Mounting a Volume, Automatic Unmounting, Operational Principles, Overview +@comment node-name, next, previous, up +@section Mounting a Volume +@cindex Mounting a volume +@cindex Location lists +@cindex Alternate locations +@cindex Mount retries +@cindex Background mounts + +Each automount point has a corresponding mount map. The mount map +contains a list of key--value pairs. The key is the name of the volume +to be mounted. The value is a list of locations describing where the +filesystem is stored in the network. In the source for the map the +value would look like + +@display +location1 location2 @dots{} locationN +@end display + +@i{Amd} examines each location in turn. Each location may contain +@dfn{selectors} which control whether @i{Amd} can use that location. +For example, the location may be restricted to use by certain hosts. +Those locations which cannot be used are ignored. + +@i{Amd} attempts to mount the filesystem described by each remaining +location until a mount succeeds or @i{Amd} can no longer proceed. The +latter can occur in three ways: + +@itemize @bullet +@item +If none of the locations could be used, or if all of the locations +caused an error, then the last error is returned. + +@item +If a location could be used but was being mounted in the background then +@i{Amd} marks that mount as being ``in progress'' and continues with +the next request; no reply is sent to the kernel. + +@item +Lastly, one or more of the mounts may have been @dfn{deferred}. A mount +is deferred if extra information is required before the mount can +proceed. When the information becomes available the mount will take +place, but in the mean time no reply is sent to the kernel. If the +mount is deferred, @i{Amd} continues to try any remaining locations. +@end itemize + +Once a volume has been mounted, @i{Amd} establishes a @dfn{volume +mapping} which is used to satisfy subsequent requests.@refill + +@node Automatic Unmounting, Keep-alives, Mounting a Volume, Overview +@comment node-name, next, previous, up +@section Automatic Unmounting + +To avoid an ever increasing number of filesystem mounts, @i{Amd} removes +volume mappings which have not been used recently. A time-to-live +interval is associated with each mapping and when that expires the +mapping is removed. When the last reference to a filesystem is removed, +that filesystem is unmounted. If the unmount fails, for example the +filesystem is still busy, the mapping is re-instated and its +time-to-live interval is extended. The global default for this grace +period is controlled by the @code{-w} command-line option (@pxref{-w +Option, -w}) or the @i{amd.conf} parameter @samp{dismount_interval} +(@pxref{dismount_interval Parameter}). It is also possible to set this +value on a per-mount basis (@pxref{opts Option, opts, opts}). + +Filesystems can be forcefully timed out using the @i{Amq} command. +@xref{Run-time Administration}. + +@node Keep-alives, Non-blocking Operation, Automatic Unmounting, Overview +@comment node-name, next, previous, up +@section Keep-alives +@cindex Keep-alives +@cindex Server crashes +@cindex NFS ping + +Use of some filesystem types requires the presence of a server on +another machine. If a machine crashes then it is of no concern to +processes on that machine that the filesystem is unavailable. However, +to processes on a remote host using that machine as a fileserver this +event is important. This situation is most widely recognized when an +NFS server crashes and the behavior observed on client machines is that +more and more processes hang. In order to provide the possibility of +recovery, @i{Amd} implements a @dfn{keep-alive} interval timer for some +filesystem types. Currently only NFS makes use of this service. + +The basis of the NFS keep-alive implementation is the observation that +most sites maintain replicated copies of common system data such as +manual pages, most or all programs, system source code and so on. If +one of those servers goes down it would be reasonable to mount one of +the others as a replacement. + +The first part of the process is to keep track of which fileservers are +up and which are down. @i{Amd} does this by sending RPC requests to the +servers' NFS @code{NullProc} and checking whether a reply is returned. +While the server state is uncertain the requests are re-transmitted at +three second intervals and if no reply is received after four attempts +the server is marked down. If a reply is received the fileserver is +marked up and stays in that state for 30 seconds at which time another +NFS ping is sent. + +Once a fileserver is marked down, requests continue to be sent every 30 +seconds in order to determine when the fileserver comes back up. During +this time any reference through @i{Amd} to the filesystems on that +server fail with the error ``Operation would block''. If a replacement +volume is available then it will be mounted, otherwise the error is +returned to the user. + +@c @i{Amd} keeps track of which servers are up and which are down. +@c It does this by sending RPC requests to the servers' NFS {\sc NullProc} and +@c checking whether a reply is returned. If no replies are received after a +@c short period, @i{Amd} marks the fileserver @dfn{down}. +@c RPC requests continue to be sent so that it will notice when a fileserver +@c comes back up. +@c ICMP echo packets \cite{rfc:icmp} are not used because it is the availability +@c of the NFS service that is important, not the existence of a base kernel. +@c Whenever a reference to a fileserver which is down is made via @i{Amd}, an alternate +@c filesystem is mounted if one is available. +@c +Although this action does not protect user files, which are unique on +the network, or processes which do not access files via @i{Amd} or +already have open files on the hung filesystem, it can prevent most new +processes from hanging. + +By default, fileserver state is not maintained for NFS/TCP mounts. The +remote fileserver is always assumed to be up. +@c +@c With a suitable combination of filesystem management and mount-maps, +@c machines can be protected against most server downtime. This can be +@c enhanced by allocating boot-servers dynamically which allows a diskless +@c workstation to be quickly restarted if necessary. Once the root filesystem +@c is mounted, @i{Amd} can be started and allowed to mount the remainder of +@c the filesystem from whichever fileservers are available. + +@node Non-blocking Operation, , Keep-alives, Overview +@comment node-name, next, previous, up +@section Non-blocking Operation +@cindex Non-blocking operation +@cindex Multiple-threaded server +@cindex RPC retries + +Since there is only one instance of @i{Amd} for each automount point, +and usually only one instance on each machine, it is important that it +is always available to service kernel calls. @i{Amd} goes to great +lengths to ensure that it does not block in a system call. As a last +resort @i{Amd} will fork before it attempts a system call that may block +indefinitely, such as mounting an NFS filesystem. Other tasks such as +obtaining filehandle information for an NFS filesystem, are done using a +purpose built non-blocking RPC library which is integrated with +@i{Amd}'s task scheduler. This library is also used to implement NFS +keep-alives (@pxref{Keep-alives}). + +Whenever a mount is deferred or backgrounded, @i{Amd} must wait for it +to complete before replying to the kernel. However, this would cause +@i{Amd} to block waiting for a reply to be constructed. Rather than do +this, @i{Amd} simply @dfn{drops} the call under the assumption that the +kernel RPC mechanism will automatically retry the request. + +@c ################################################################ +@node Supported Platforms, Mount Maps, Overview, Top +@comment node-name, next, previous, up +@chapter Supported Platforms +@cindex Supported Platforms +@cindex shared libraries +@cindex NFS V.3 support + +@i{Am-utils} has been ported to a wide variety of machines and operating +systems. @i{Am-utils}'s code works for little-endian and big-endian +machines, as well as 32 bit and 64 bit architectures. Furthermore, when +@i{Am-utils} ports to an Operating System on one architecture, it is generally +readily portable to the same Operating System on all platforms on which +it is available. + +The table below lists those platforms supported by the latest release. +The listing is based on the standard output from GNU's +@code{config.guess} script. Since significant changes have been made to +am-utils, not all systems listed here have been verified working for all +features. + +@multitable {Auto-Configured System Name} {Config} {Compile} {Amd} {NFS3} {Shlib} {Hlfsd} + +@item @b{Auto-Configured System Name} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab @b{Config} @tab @b{Compile} @tab @b{Amd} @tab @b{NFS3} @tab @b{Shlib} @tab @b{Hlfsd} + +@item @b{alpha-dec-osf2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab @tab @tab + +@item @b{alpha-dec-osf4.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{alphaev5-unknown-linux-gnu} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{hppa1.0-hp-hpux11.00} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab no @tab @tab + +@item @b{hppa1.1-hp-hpux10.10} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab no @tab + +@item @b{hppa1.1-hp-hpux10.20} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab no @tab + +@item @b{hppa1.1-hp-hpux9.01} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{hppa1.1-hp-hpux9.05} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{hppa1.1-hp-hpux9.07} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi3.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-bsdi3.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-pc-solaris2.5.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{i386-pc-solaris2.6} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{i386-unknown-freebsd2.1.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{i386-unknown-freebsd2.2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i386-unknown-freebsd3.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-netbsd1.3.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i386-unknown-openbsd2.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{i486-ncr-sysv4.3.03} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab @tab yes @tab @tab + +@item @b{i486-pc-linux-gnulibc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i586-pc-linux-gnulinc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{i686-pc-linux-gnu} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{m68k-hp-hpux9.00} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{m68k-sun-sunos4.1.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{m68k-next-nextstep3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{mips-dec-ultrix4.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{mips-sgi-irix5.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab @tab @tab @tab @tab @tab + +@item @b{mips-sgi-irix5.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{mips-sgi-irix6.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{mips-sgi-irix6.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{powerpc-ibm-aix4.1.5.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{powerpc-ibm-aix4.2.1.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab @tab + +@item @b{rs6000-ibm-aix3.2} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix3.2.5} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix4.1.4.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{rs6000-ibm-aix4.1.5.0} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{sparc-sun-solaris2.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab @tab + +@item @b{sparc-sun-solaris2.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-solaris2.5} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab + +@item @b{sparc-sun-solaris2.5.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{sparc-sun-solaris2.6} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab yes @tab yes @tab yes + +@item @b{sparc-sun-sunos4.1.1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3C} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.3_U1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-sun-sunos4.1.4} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-unknown-linux-gnulibc1} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab n/a @tab yes @tab + +@item @b{sparc-unknown-netbsd1.2E} +@c {Config} {Compile} {Amd} {NFS V.3} {Shlib} {Hlfsd} +@tab yes @tab yes @tab yes @tab @tab @tab + +@end multitable + +See the @file{INSTALL} in the distribution for more specific details on +building and/or configuring for some systems. + +@c ################################################################ +@node Mount Maps, Amd Command Line Options, Supported Platforms, Top +@comment node-name, next, previous, up +@chapter Mount Maps +@cindex Mount maps +@cindex Automounter configuration maps +@cindex Mount information + +@i{Amd} has no built-in knowledge of machines or filesystems. +External @dfn{mount-maps} are used to provide the required information. +Specifically, @i{Amd} needs to know when and under what conditions it +should mount filesystems. + +The map entry corresponding to the requested name contains a list of +possible locations from which to resolve the request. Each location +specifies filesystem type, information required by that filesystem (for +example the block special device in the case of UFS), and some +information describing where to mount the filesystem (@pxref{fs Option}). A +location may also contain @dfn{selectors} (@pxref{Selectors}).@refill + +@menu +* Map Types:: +* Key Lookup:: +* Location Format:: +@end menu + +@node Map Types, Key Lookup, Mount Maps, Mount Maps +@comment node-name, next, previous, up +@section Map Types +@cindex Mount map types +@cindex Map types +@cindex Configuration map types +@cindex Types of mount map +@cindex Types of configuration map +@cindex Determining the map type + +A mount-map provides the run-time configuration information to @i{Amd}. +Maps can be implemented in many ways. Some of the forms supported by +@i{Amd} are regular files, ndbm databases, NIS maps, the @dfn{Hesiod} +name server, and even the password file. + +A mount-map @dfn{name} is a sequence of characters. When an automount +point is created a handle on the mount-map is obtained. For each map +type configured, @i{Amd} attempts to reference the map of the +appropriate type. If a map is found, @i{Amd} notes the type for future +use and deletes the reference, for example closing any open file +descriptors. The available maps are configured when @i{Amd} is built +and can be displayed by running the command @samp{amd -v}. + +When using an @i{Amd} configuration file (@pxref{Amd Configuration File}) +and the keyword @samp{map_type} (@pxref{map_type Parameter}), you may +force the map used to any type. + +By default, @i{Amd} caches data in a mode dependent on the type of map. +This is the same as specifying @samp{cache:=mapdefault} and selects a +suitable default cache mode depending on the map type. The individual +defaults are described below. The @var{cache} option can be specified +on automount points to alter the caching behavior (@pxref{Automount +Filesystem}).@refill + +The following map types have been implemented, though some are not +available on all machines. Run the command @samp{amd -v} to obtain a +list of map types configured on your machine. + +@menu +* File maps:: +* ndbm maps:: +* NIS maps:: +* NIS+ maps:: +* Hesiod maps:: +* Password maps:: +* Union maps:: +* LDAP maps:: +@end menu + +@node File maps, ndbm maps, Map Types, Map Types +@comment node-name, next, previous, up +@subsection File maps +@cindex File maps +@cindex Flat file maps +@cindex File map syntactic conventions + +When @i{Amd} searches a file for a map entry it does a simple scan of +the file and supports both comments and continuation lines. + +Continuation lines are indicated by a backslash character (@samp{\}) as +the last character of a line in the file. The backslash, newline character +@emph{and any leading white space on the following line} are discarded. A maximum +line length of 2047 characters is enforced after continuation lines are read +but before comments are stripped. Each line must end with +a newline character; that is newlines are terminators, not separators. +The following examples illustrate this: + +@example +key valA valB; \ + valC +@end example + +specifies @emph{three} locations, and is identical to + +@example +key valA valB; valC +@end example + +However, + +@example +key valA valB;\ + valC +@end example + +specifies only @emph{two} locations, and is identical to + +@example +key valA valB;valC +@end example + +After a complete line has been read from the file, including +continuations, @i{Amd} determines whether there is a comment on the +line. A comment begins with a hash (``@samp{#}'') character and +continues to the end of the line. There is no way to escape or change +the comment lead-in character. + +Note that continuation lines and comment support @dfn{only} apply to +file maps, or ndbm maps built with the @code{mk-amd-map} program. + +When caching is enabled, file maps have a default cache mode of +@code{all} (@pxref{Automount Filesystem}). + +@node ndbm maps, NIS maps, File maps, Map Types +@comment node-name, next, previous, up +@subsection ndbm maps +@cindex ndbm maps + +An ndbm map may be used as a fast access form of a file map. The program, +@code{mk-amd-map}, converts a normal map file into an ndbm database. +This program supports the same continuation and comment conventions that +are provided for file maps. Note that ndbm format files may @emph{not} +be sharable across machine architectures. The notion of speed generally +only applies to large maps; a small map, less than a single disk block, +is almost certainly better implemented as a file map. + +ndbm maps have a default cache mode of @samp{all} (@pxref{Automount Filesystem}). + +@node NIS maps, NIS+ maps, ndbm maps, Map Types +@comment node-name, next, previous, up +@subsection NIS maps +@cindex NIS (YP) maps + +When using NIS (formerly YP), an @i{Amd} map is implemented directly +by the underlying NIS map. Comments and continuation lines are +@emph{not} supported in the automounter and must be stripped when +constructing the NIS server's database. + +NIS maps have a default cache mode of @code{all} (@pxref{Automount +Filesystem}). + +The following rule illustrates what could be added to your NIS @file{Makefile}, +in this case causing the @file{amd.home} map to be rebuilt: +@example +$(YPTSDIR)/amd.home.time: $(ETCDIR)/amd.home + -@@sed -e "s/#.*$$//" -e "/^$$/d" $(ETCDIR)/amd.home | \ + awk '@{ \ + for (i = 1; i <= NF; i++) \ + if (i == NF) @{ \ + if (substr($$i, length($$i), 1) == "\\") \ + printf("%s", substr($$i, 1, length($$i) - 1)); \ + else \ + printf("%s\n", $$i); \ + @} \ + else \ + printf("%s ", $$i); \ + @}' | \ + $(MAKEDBM) - $(YPDBDIR)/amd.home; \ + touch $(YPTSDIR)/amd.home.time; \ + echo "updated amd.home"; \ + if [ ! $(NOPUSH) ]; then \ + $(YPPUSH) amd.home; \ + echo "pushed amd.home"; \ + else \ + : ; \ + fi +@end example + +Here @code{$(YPTSDIR)} contains the time stamp files, and @code{$(YPDBDIR)} contains +the dbm format NIS files. + +@node NIS+ maps, Hesiod maps, NIS maps, Map Types +@comment node-name, next, previous, up +@subsection NIS+ maps +@cindex NIS+ maps + +NIS+ maps do not support cache mode @samp{all} and, when caching is +enabled, have a default cache mode of @samp{inc}. + +XXX: FILL IN WITH AN EXAMPLE. + +@node Hesiod maps, Password maps, NIS+ maps, Map Types +@comment node-name, next, previous, up +@subsection Hesiod maps +@cindex Hesiod maps + +When the map name begins with the string @samp{hesiod.} lookups are made +using the @dfn{Hesiod} name server. The string following the dot is +used as a name qualifier and is prepended with the key being located. +The entire string is then resolved in the @code{automount} context, or +the @i{amd.conf} parameter @samp{hesiod_base} (@pxref{hesiod_base +Parameter}). For example, if the the key is @samp{jsp} and map name is +@samp{hesiod.homes} then @dfn{Hesiod} is asked to resolve +@samp{jsp.homes.automount}. + +Hesiod maps do not support cache mode @samp{all} and, when caching is +enabled, have a default cache mode of @samp{inc} (@pxref{Automount +Filesystem}). + +The following is an example of a @dfn{Hesiod} map entry: + +@example +jsp.homes.automount HS TXT "rfs:=/home/charm;rhost:=charm;sublink:=jsp" +njw.homes.automount HS TXT "rfs:=/home/dylan/dk2;rhost:=dylan;sublink:=njw" +@end example + +@node Password maps, Union maps, Hesiod maps, Map Types +@comment node-name, next, previous, up +@subsection Password maps +@cindex Password file maps +@cindex /etc/passwd maps +@cindex User maps, automatic generation +@cindex Automatic generation of user maps +@cindex Using the password file as a map + +The password map support is unlike the four previous map types. When +the map name is the string @file{/etc/passwd} @i{Amd} can lookup a user +name in the password file and re-arrange the home directory field to +produce a usable map entry. + +@i{Amd} assumes the home directory has the format +`@t{/}@i{anydir}@t{/}@i{dom1}@t{/../}@i{domN}@t{/}@i{login}'. +@c @footnote{This interpretation is not necessarily exactly what you want.} +It breaks this string into a map entry where @code{$@{rfs@}} has the +value `@t{/}@i{anydir}@t{/}@i{domN}', @code{$@{rhost@}} has the value +`@i{domN}@t{.}@i{...}@t{.}@i{dom1}', and @code{$@{sublink@}} has the +value @i{login}.@refill + +Thus if the password file entry was + +@example +/home/achilles/jsp +@end example + +the map entry used by @i{Amd} would be + +@example +rfs:=/home/achilles;rhost:=achilles;sublink:=jsp +@end example + +Similarly, if the password file entry was + +@example +/home/cc/sugar/mjh +@end example + +the map entry used by @i{Amd} would be + +@example +rfs:=/home/sugar;rhost:=sugar.cc;sublink:=jsp +@end example + +@node Union maps, LDAP maps , Password maps, Map Types +@comment node-name, next, previous, up +@subsection Union maps +@cindex Union file maps + +The union map support is provided specifically for use with the union +filesystem, @pxref{Union Filesystem}. + +It is identified by the string @samp{union:} which is followed by a +colon separated list of directories. The directories are read in order, +and the names of all entries are recorded in the map cache. Later +directories take precedence over earlier ones. The union filesystem +type then uses the map cache to determine the union of the names in all +the directories. + +@node LDAP maps, , Union maps, Map Types +@comment node-name, next, previous, up +@subsection LDAP maps +@cindex LDAP maps +@cindex Lightweight Directory Access Protocol + +LDAP (Lightweight Directory Access Protocol) maps do not support cache +mode @samp{all} and, when caching is enabled, have a default cache mode +of @samp{inc}. + +For example, an @i{Amd} map @samp{amd.home} that looks as follows: + +@example +/defaults opts:=rw,intr;type:=link + +zing -rhost:=shekel \ + host==shekel \ + host!=shekel;type:=nfs +@end example +@noindent +when converted to LDAP (@pxref{amd2ldif}), will result in the following +LDAP database: +@example +$ amd2ldif amd.home CUCS < amd.home +dn: cn=amdmap timestamp, CUCS +cn : amdmap timestamp +objectClass : amdmapTimestamp +amdmapTimestamp: 873071363 + +dn: cn=amdmap amd.home[/defaults], CUCS +cn : amdmap amd.home[/defaults] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : /defaults +amdmapValue : opts:=rw,intr;type:=link + +dn: cn=amdmap amd.home[], CUCS +cn : amdmap amd.home[] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : +amdmapValue : + +dn: cn=amdmap amd.home[zing], CUCS +cn : amdmap amd.home[zing] +objectClass : amdmap +amdmapName : amd.home +amdmapKey : zing +amdmapValue : -rhost:=shekel host==shekel host!=shekel;type:=nfs +@end example + +@c subsection Gdbm + +@node Key Lookup, Location Format, Map Types, Mount Maps +@comment node-name, next, previous, up +@section How keys are looked up +@cindex Key lookup +@cindex Map lookup +@cindex Looking up keys +@cindex How keys are looked up +@cindex Wildcards in maps + +The key is located in the map whose type was determined when the +automount point was first created. In general the key is a pathname +component. In some circumstances this may be modified by variable +expansion (@pxref{Variable Expansion}) and prefixing. If the automount +point has a prefix, specified by the @var{pref} option, then that is +prepended to the search key before the map is searched. + +If the map cache is a @samp{regexp} cache then the key is treated as an +egrep-style regular expression, otherwise a normal string comparison is +made. + +If the key cannot be found then a @dfn{wildcard} match is attempted. +@i{Amd} repeatedly strips the basename from the key, appends @samp{/*} and +attempts a lookup. Finally, @i{Amd} attempts to locate the special key @samp{*}. + +For example, the following sequence would be checked if @file{home/dylan/dk2} was +being located: + +@example + home/dylan/dk2 + home/dylan/* + home/* + * +@end example + +At any point when a wildcard is found, @i{Amd} proceeds as if an exact +match had been found and the value field is then used to resolve the +mount request, otherwise an error code is propagated back to the kernel. +(@pxref{Filesystem Types}).@refill + +@node Location Format, , Key Lookup, Mount Maps +@comment node-name, next, previous, up +@section Location Format +@cindex Location format +@cindex Map entry format +@cindex How locations are parsed + +The value field from the lookup provides the information required to +mount a filesystem. The information is parsed according to the syntax +shown below. + +@display +@i{location-list}: + @i{location-selection} + @i{location-list} @i{white-space} @t{||} @i{white-space} @i{location-selection} +@i{location-selection}: + @i{location} + @i{location-selection} @i{white-space} @i{location} +@i{location}: + @i{location-info} + @t{-}@i{location-info} + @t{-} +@i{location-info}: + @i{sel-or-opt} + @i{location-info}@t{;}@i{sel-or-opt} + @t{;} +@i{sel-or-opt}: + @i{selection} + @i{opt-ass} +@i{selection}: + selector@t{==}@i{value} + selector@t{!=}@i{value} +@i{opt-ass}: + option@t{:=}@i{value} +@i{white-space}: + space + tab +@end display + +Note that unquoted whitespace is not allowed in a location description. +White space is only allowed, and is mandatory, where shown with non-terminal +@i{white-space}. + +A @dfn{location-selection} is a list of possible volumes with which to +satisfy the request. @dfn{location-selection}s are separated by the +@samp{||} operator. The effect of this operator is to prevent use of +location-selections to its right if any of the location-selections on +its left were selected whether or not any of them were successfully +mounted (@pxref{Selectors}).@refill + +The location-selection, and singleton @dfn{location-list}, +@samp{type:=ufs;dev:=/dev/xd1g} would inform @i{Amd} to mount a UFS +filesystem from the block special device @file{/dev/xd1g}. + +The @dfn{sel-or-opt} component is either the name of an option required +by a specific filesystem, or it is the name of a built-in, predefined +selector such as the architecture type. The value may be quoted with +double quotes @samp{"}, for example +@samp{type:="ufs";dev:="/dev/xd1g"}. These quotes are stripped when the +value is parsed and there is no way to get a double quote into a value +field. Double quotes are used to get white space into a value field, +which is needed for the program filesystem (@pxref{Program Filesystem}).@refill + +@menu +* Map Defaults:: +* Variable Expansion:: +* Selectors:: +* Map Options:: +@end menu + +@node Map Defaults, Variable Expansion, Location Format, Location Format +@comment node-name, next, previous, up +@subsection Map Defaults +@cindex Map defaults +@cindex How to set default map parameters +@cindex Setting default map parameters + +A location beginning with a dash @samp{-} is used to specify default +values for subsequent locations. Any previously specified defaults in +the location-list are discarded. The default string can be empty in +which case no defaults apply. + +The location @samp{-fs:=/mnt;opts:=ro} would set the local mount point +to @file{/mnt} and cause mounts to be read-only by default. Defaults +specified this way are appended to, and so override, any global map +defaults given with @samp{/defaults}). + +@c +@c A @samp{/defaults} value @dfn{gdef} and a location list +@c \begin{quote} +@c $@samp{-}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$ +@c \end{quote} +@c is equivalent to +@c \begin{quote} +@c $@samp{-}@dfn{gdef}@samp{;}@dfn{def}_a $\verb*+ +$ @dfn{loc}_{a_1} $\verb*+ +$ @dfn{loc}_{a_2} $\verb*+ +$ @samp{-}@dfn{gdef}@samp{;}@dfn{def}_b $\verb*+ +$ @dfn{loc}_{b_1} \ldots$ +@c \end{quote} +@c which is equivalent to +@c \begin{quote} +@c $@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_1} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_a@samp{;}@dfn{loc}_{a_2} $\verb*+ +$@dfn{gdef}@samp{;}@dfn{def}_b@samp{;}@dfn{loc}_{b_1} \ldots$ +@c \end{quote} + +@node Variable Expansion, Selectors, Map Defaults, Location Format +@comment node-name, next, previous, up +@subsection Variable Expansion +@cindex Variable expansion +@cindex How variables are expanded +@cindex Pathname operators +@cindex Domain stripping +@cindex Domainname operators +@cindex Stripping the local domain name +@cindex Environment variables +@cindex How to access environment variables in maps + +To allow generic location specifications @i{Amd} does variable expansion +on each location and also on some of the option strings. Any option or +selector appearing in the form @code{$@dfn{var}} is replaced by the +current value of that option or selector. For example, if the value of +@code{$@{key@}} was @samp{bin}, @code{$@{autodir@}} was @samp{/a} and +@code{$@{fs@}} was `@t{$@{autodir@}}@t{/local/}@t{$@{key@}}' then +after expansion @code{$@{fs@}} would have the value @samp{/a/local/bin}. +Any environment variable can be accessed in a similar way.@refill + +Two pathname operators are available when expanding a variable. If the +variable name begins with @samp{/} then only the last component of the +pathname is substituted. For example, if @code{$@{path@}} was +@samp{/foo/bar} then @code{$@{/path@}} would be expanded to @samp{bar}. +Similarly, if the variable name ends with @samp{/} then all but the last +component of the pathname is substituted. In the previous example, +@code{$@{path/@}} would be expanded to @samp{/foo}.@refill + +Two domain name operators are also provided. If the variable name +begins with @samp{.} then only the domain part of the name is +substituted. For example, if @code{$@{rhost@}} was +@samp{swan.doc.ic.ac.uk} then @code{$@{.rhost@}} would be expanded to +@samp{doc.ic.ac.uk}. Similarly, if the variable name ends with @samp{.} +then only the host component is substituted. In the previous example, +@code{$@{rhost.@}} would be expanded to @samp{swan}.@refill + +Variable expansion is a two phase process. Before a location is parsed, +all references to selectors, @i{eg} @code{$@{path@}}, are expanded. The +location is then parsed, selections are evaluated and option assignments +recorded. If there were no selections or they all succeeded the +location is used and the values of the following options are expanded in +the order given: @var{sublink}, @var{rfs}, @var{fs}, @var{opts}, +@var{remopts}, @var{mount} and @var{unmount}. + +Note that expansion of option values is done after @dfn{all} assignments +have been completed and not in a purely left to right order as is done +by the shell. This generally has the desired effect but care must be +taken if one of the options references another, in which case the +ordering can become significant. + +There are two special cases concerning variable expansion: + +@enumerate +@item +before a map is consulted, any selectors in the name received +from the kernel are expanded. For example, if the request from the +kernel was for `@t{$@{arch@}}@t{.bin}' and the machine architecture +was @samp{vax}, the value given to @code{$@{key@}} would be +@samp{vax.bin}.@refill + +@item +the value of @code{$@{rhost@}} is expanded and normalized before the +other options are expanded. The normalization process strips any local +sub-domain components. For example, if @code{$@{domain@}} was +@samp{Berkeley.EDU} and @code{$@{rhost@}} was initially +@samp{snow.Berkeley.EDU}, after the normalization it would simply be +@samp{snow}. Hostname normalization is currently done in a +@emph{case-dependent} manner.@refill +@end enumerate + +@c====================================================================== +@node Selectors, Map Options, Variable Expansion, Location Format +@comment node-name, next, previous, up +@subsection Selectors +@cindex Selectors + +Selectors are used to control the use of a location. It is possible to +share a mount map between many machines in such a way that filesystem +location, architecture and operating system differences are hidden from +the users. A selector of the form @samp{arch==sun3;os==sunos4} would only +apply on Sun-3s running SunOS 4.x. + +Selectors can be negated by using @samp{!=} instead of @samp{==}. For +example to select a location on all non-Vax machines the selector +@samp{arch!=vax} would be used. + +Selectors are evaluated left to right. If a selector fails then that +location is ignored. Thus the selectors form a conjunction and the +locations form a disjunction. If all the locations are ignored or +otherwise fail then @i{Amd} uses the @dfn{error} filesystem +(@pxref{Error Filesystem}). This is equivalent to having a location +@samp{type:=error} at the end of each mount-map entry.@refill + +The default value of many of the selectors listed here can be overridden +by an @i{Amd} command line switch or in an @i{Amd} configuration file. +@xref{Amd Configuration File}. + +These are the selectors currently implemented. + +@menu +* arch Selector Variable:: +* autodir Selector Variable:: +* byte Selector Variable:: +* cluster Selector Variable:: +* domain Selector Variable:: +* host Selector Variable:: +* hostd Selector Variable:: +* karch Selector Variable:: +* os Selector Variable:: +* osver Selector Variable:: + +* key Selector Variable:: +* map Selector Variable:: +* netnumber Selector Variable:: +* network Selector Variable:: +* path Selector Variable:: +* wire Selector Variable:: + +* exists Selector Function:: +* false Selector Function:: +* netgrp Selector Function:: +* in_network Selector Function:: +* true Selector Function:: +@end menu + +@c ---------------------------------------------------------------- +@node arch Selector Variable, autodir Selector Variable, Selectors, Selectors +@comment node-name, next, previous, up +@subsubsection arch Selector Variable +@cindex arch Selector Variable +@cindex arch, mount selector +@cindex Mount selector; arch +@cindex Selector; arch + +The machine architecture which was automatically determined at compile +time. The architecture type can be displayed by running the command +@samp{amd -v}. @xref{Supported Platforms}.@refill + +@c ---------------------------------------------------------------- +@node autodir Selector Variable, byte Selector Variable, arch Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection autodir Selector Variable +@cindex autodir Selector Variable +@cindex autodir, mount selector +@cindex Mount selector; autodir +@cindex Selector; autodir + +The default directory under which to mount filesystems. This may be +changed by the @code{-a} command line option. @xref{fs Option}. + +@c ---------------------------------------------------------------- +@node byte Selector Variable, cluster Selector Variable, autodir Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection byte Selector Variable +@cindex byte Selector Variable +@cindex byte, mount selector +@cindex Mount selector; byte +@cindex Selector; byte + +The machine's byte ordering. This is either @samp{little}, indicating +little-endian, or @samp{big}, indicating big-endian. One possible use +is to share @samp{rwho} databases (@pxref{rwho servers}). Another is to +share ndbm databases, however this use can be considered a courageous +juggling act. + +@c ---------------------------------------------------------------- +@node cluster Selector Variable, domain Selector Variable, byte Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection cluster Selector Variable +@cindex cluster Selector Variable +@cindex cluster, mount selector +@cindex Mount selector; cluster +@cindex Selector; cluster + +This is provided as a hook for the name of the local cluster. This can +be used to decide which servers to use for copies of replicated +filesystems. @code{$@{cluster@}} defaults to the value of +@code{$@{domain@}} unless a different value is set with the @code{-C} +command line option. + +@c ---------------------------------------------------------------- +@node domain Selector Variable, host Selector Variable, cluster Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection domain Selector Variable +@cindex domain Selector Variable +@cindex domain, mount selector +@cindex Mount selector; domain +@cindex Selector; domain + +The local domain name as specified by the @code{-d} command line option. +@xref{host Selector Variable}. + +@c ---------------------------------------------------------------- +@node host Selector Variable, hostd Selector Variable, domain Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection host Selector Variable +@cindex host Selector Variable +@cindex host, mount selector +@cindex Mount selector; host +@cindex Selector; host + +The local hostname as determined by @b{gethostname}(2). If no domain +name was specified on the command line and the hostname contains a +period @samp{.} then the string before the period is used as the host +name, and the string after the period is assigned to @code{$@{domain@}}. +For example, if the hostname is @samp{styx.doc.ic.ac.uk} then +@code{host} would be @samp{styx} and @code{domain} would be +@samp{doc.ic.ac.uk}. @code{hostd} would be +@samp{styx.doc.ic.ac.uk}.@refill + +@c ---------------------------------------------------------------- +@node hostd Selector Variable, karch Selector Variable, host Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection hostd Selector Variable +@cindex hostd Selector Variable +@cindex hostd, mount selector +@cindex Mount selector; hostd +@cindex Selector; hostd + +This resolves to the @code{$@{host@}} and @code{$@{domain@}} +concatenated with a @samp{.} inserted between them if required. If +@code{$@{domain@}} is an empty string then @code{$@{host@}} and +@code{$@{hostd@}} will be identical. + +@c ---------------------------------------------------------------- +@node karch Selector Variable, os Selector Variable, hostd Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection karch Selector Variable +@cindex karch Selector Variable +@cindex karch, mount selector +@cindex Mount selector; karch +@cindex Selector; karch + +This is provided as a hook for the kernel architecture. This is used on +SunOS 4 and SunOS 5, for example, to distinguish between different +@samp{/usr/kvm} volumes. @code{$@{karch@}} defaults to the ``machine'' +value gotten from @b{uname}(2). If the @b{uname}(2) system call is not +available, the value of @code{$@{karch@}} defaults to that of +@code{$@{arch@}}. Finally, a different value can be set with the @code{-k} +command line option. + +@c ---------------------------------------------------------------- +@node os Selector Variable, osver Selector Variable, karch Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection os Selector Variable +@cindex os Selector Variable +@cindex os, mount selector +@cindex Mount selector; os +@cindex Selector; os + +The operating system. Like the machine architecture, this is +automatically determined at compile time. The operating system name can +be displayed by running the command @samp{amd -v}. @xref{Supported +Platforms}.@refill + +@c ---------------------------------------------------------------- +@node osver Selector Variable, key Selector Variable, os Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection osver Selector Variable +@cindex osver Selector Variable +@cindex osver, mount selector +@cindex Mount selector; osver +@cindex Selector; osver + +The operating system version. Like the machine architecture, this is +automatically determined at compile time. The operating system name can +be displayed by running the command @samp{amd -v}. @xref{Supported +Platforms}.@refill + +@c ---------------------------------------------------------------- +@ifhtml +<HR> +@end ifhtml +@sp 3 +The following selectors are also provided. Unlike the other selectors, +they vary for each lookup. Note that when the name from the kernel is +expanded prior to a map lookup, these selectors are all defined as empty +strings. + +@c ---------------------------------------------------------------- +@node key Selector Variable, map Selector Variable, osver Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection key Selector Variable +@cindex key Selector Variable +@cindex key, mount selector +@cindex Mount selector; key +@cindex Selector; key + +The name being resolved. For example, if @file{/home} is an automount +point, then accessing @file{/home/foo} would set @code{$@{key@}} to the +string @samp{foo}. The key is prefixed by the @var{pref} option set in +the parent mount point. The default prefix is an empty string. If the +prefix was @file{blah/} then @code{$@{key@}} would be set to +@file{blah/foo}.@refill + +@c ---------------------------------------------------------------- +@node map Selector Variable, netnumber Selector Variable, key Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection map Selector Variable +@cindex map Selector Variable +@cindex map, mount selector +@cindex Mount selector; map +@cindex Selector; map + +The name of the mount map being used. + +@c ---------------------------------------------------------------- +@node netnumber Selector Variable, network Selector Variable, map Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection netnumber Selector Variable +@cindex netnumber Selector Variable +@cindex netnumber, mount selector +@cindex Mount selector; netnumber +@cindex Selector; netnumber + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@node network Selector Variable, path Selector Variable, netnumber Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection network Selector Variable +@cindex network Selector Variable +@cindex network, mount selector +@cindex Mount selector; network +@cindex Selector; network + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@node path Selector Variable, wire Selector Variable, network Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection path Selector Variable +@cindex path Selector Variable +@cindex path, mount selector +@cindex Mount selector; path +@cindex Selector; path + +The full pathname of the name being resolved. For example +@file{/home/foo} in the example above. + +@c ---------------------------------------------------------------- +@node wire Selector Variable, exists Selector Function, path Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection wire Selector Variable +@cindex wire Selector Variable +@cindex wire, mount selector +@cindex Mount selector; wire +@cindex Selector; wire + +This selector is identical to the @samp{in_network} selector function, +see @ref{in_network Selector Function}. It will match either the name +or number of @i{any} network interface on which this host is connected +to. The names and numbers of all attached interfaces are available from +the output of @samp{amd -v}. + +@c ---------------------------------------------------------------- +@ifhtml +<HR> +@end ifhtml +@sp 2 +The following boolean functions are selectors which take an argument +@i{ARG}. They return a value of true or false, and thus do not need to +be compared with a value. Each of these may be negated by prepending +@samp{!} to their name. + +@c ---------------------------------------------------------------- +@node exists Selector Function, false Selector Function, wire Selector Variable, Selectors +@comment node-name, next, previous, up +@subsubsection exists Selector Function +@cindex exists Selector Function +@cindex exists, boolean mount selector +@cindex !exists, boolean mount selector +@cindex Mount selector; exists +@cindex Selector; exists + +If the file listed by @i{ARG} exists (via @b{lstat}(2)), this function +evaluates to true. Otherwise it evaluates to false. + +@c ---------------------------------------------------------------- +@node false Selector Function, netgrp Selector Function, exists Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection false Selector Function +@cindex false Selector Function +@cindex false, boolean mount selector +@cindex !false, boolean mount selector +@cindex Mount selector; false +@cindex Selector; false + +Always evaluates to false. @i{ARG} is ignored. + +@c ---------------------------------------------------------------- +@node netgrp Selector Function, in_network Selector Function, false Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection netgrp Selector Function +@cindex netgrp Selector Function +@cindex netgrp, boolean mount selector +@cindex !netgrp, boolean mount selector +@cindex Mount selector; netgrp +@cindex Selector; netgrp + +If the current host as determined by the value of @code{$@{host@}} is a +member of the netgroup @i{ARG}, this selector evaluates to true. +Otherwise it evaluates to false. + +For example, suppose you have a netgroup @samp{ppp-hosts}, and for +reasons of performance, these have a local @file{/home} partition, while +all other clients on the faster network can access a shared home +directory. A common map to use for both might look like the following: + +@example +home/* netgrp(ppp-hosts);type:=link;fs:=/local/$@{key@} \ + !netgrp(ppp-hosts);type:=nfs;rhost=serv1;rfs:=/remote/$@{key@} +@end example + +@c ---------------------------------------------------------------- +@node in_network Selector Function, true Selector Function, netgrp Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection in_network Selector Function +@cindex in_network Selector Function +@cindex in_network, boolean mount selector +@cindex !in_network, boolean mount selector +@cindex Mount selector; in_network +@cindex Selector; in_network + +If the current host has any network interface that is locally attached +to the network specified in @i{ARG} (either via name or number), this +selector evaluates to true. Otherwise it evaluates to false. + +For example, suppose you have two servers that have an exportable +@file{/opt} that smaller clients can NFS mount. The two servers are +say, @samp{serv1} on network @samp{foo-net.site.com} and @samp{serv2} on +network @samp{123.4.5.0}. You can write a map to be used by all clients +that will attempt to mount the closest one as follows: + +@example +opt in_network(foo-net.site.com);rhost:=serv1;rfs:=/opt \ + in_network(123.4.5.0);rhost:=serv2;rfs:=/opt \ + rhost:=fallback-server +@end example + +@c ---------------------------------------------------------------- +@node true Selector Function, , in_network Selector Function, Selectors +@comment node-name, next, previous, up +@subsubsection true Selector Function +@cindex true Selector Function +@cindex true, boolean mount selector +@cindex !true, boolean mount selector +@cindex Mount selector; true +@cindex Selector; true + +Always evaluates to true. @i{ARG} is ignored. + +@c ================================================================ +@node Map Options, , Selectors, Location Format +@comment node-name, next, previous, up +@subsection Map Options +@cindex Map options +@cindex Setting map options + +Options are parsed concurrently with selectors. The difference is that +when an option is seen the string following the @samp{:=} is +recorded for later use. As a minimum the @var{type} option must be +specified. Each filesystem type has other options which must also be +specified. @xref{Filesystem Types}, for details on the filesystem +specific options.@refill + +Superfluous option specifications are ignored and are not reported +as errors. + +The following options apply to more than one filesystem type. + +@menu +* addopts Option:: +* delay Option:: +* fs Option:: +* opts Option:: +* remopts Option:: +* sublink Option:: +* type Option:: +@end menu + +@node addopts Option, delay Option, Map Options, Map Options +@comment node-name, next, previous, up +@subsubsection addopts Option +@cindex Setting additional options on a mount location +@cindex Overriding or adding options to a mount +@cindex addopts, mount option +@cindex Mount option; addopts + +This option adds additional options to default options normally +specified in the @samp{/defaults} entry or the defaults of the key entry +being processed (@xref{opts Option}). Normally when you specify +@samp{opts} in both the @samp{/defaults} and the map entry, the latter +overrides the former completely. But with @samp{addopts} it will +append the options and override any conflicting ones. + +Options which start with @samp{no} will override those with the same +name that do not start with @samp{no} and vice verse. Special handling +is given to inverted options such as @samp{soft} and @samp{hard}, +@samp{bg} and @samp{fg}, @samp{ro} and @samp{rw}, etc. + +For example, if the default options specified were +@example +opts:=rw,nosuid,intr,rsize=1024,wsize=1024,quota,posix +@end example + +and the ones specified in a map entry were + +@example +addopts:=grpid,suid,ro,rsize=2048,quota,nointr +@end example + +then the actual options used would be + +@example +wsize=1024,posix,grpid,suid,ro,rsize=2048,quota,nointr +@end example + +@node delay Option, fs Option, addopts Option, Map Options +@comment node-name, next, previous, up +@subsubsection delay Option +@cindex Setting a delay on a mount location +@cindex Delaying mounts from specific locations +@cindex Primary server +@cindex Secondary server +@cindex delay, mount option +@cindex Mount option; delay + +The delay, in seconds, before an attempt will be made to mount from the +current location. Auxiliary data, such as network address, file handles +and so on are computed regardless of this value. + +A delay can be used to implement the notion of primary and secondary +file servers. The secondary servers would have a delay of a few +seconds, thus giving the primary servers a chance to respond first. + +@node fs Option, opts Option, delay Option, Map Options +@comment node-name, next, previous, up +@subsubsection fs Option +@cindex Setting the local mount point +@cindex Overriding the default mount point +@cindex fs, mount option +@cindex Mount option; fs + +The local mount point. The semantics of this option vary between +filesystems. + +For NFS and UFS filesystems the value of @code{$@{fs@}} is used as the +local mount point. For other filesystem types it has other meanings +which are described in the section describing the respective filesystem +type. It is important that this string uniquely identifies the +filesystem being mounted. To satisfy this requirement, it should +contain the name of the host on which the filesystem is resident and the +pathname of the filesystem on the local or remote host. + +The reason for requiring the hostname is clear if replicated filesystems +are considered. If a fileserver goes down and a replacement filesystem +is mounted then the @dfn{local} mount point @dfn{must} be different from +that of the filesystem which is hung. Some encoding of the filesystem +name is required if more than one filesystem is to be mounted from any +given host. + +If the hostname is first in the path then all mounts from a particular +host will be gathered below a single directory. If that server goes +down then the hung mount points are less likely to be accidentally +referenced, for example when @b{getcwd}(3) traverses the namespace to +find the pathname of the current directory. + +The @samp{fs} option defaults to +@code{$@{autodir@}/$@{rhost@}$@{rfs@}}. In addition, +@samp{rhost} defaults to the local host name (@code{$@{host@}}) and +@samp{rfs} defaults to the value of @code{$@{path@}}, which is the full +path of the requested file; @samp{/home/foo} in the example above +(@pxref{Selectors}). @code{$@{autodir@}} defaults to @samp{/a} but may +be changed with the @code{-a} command line option. Sun's automounter +defaults to @samp{/tmp_mnt}. Note that there is no @samp{/} between +the @code{$@{rhost@}} and @code{$@{rfs@}} since @code{$@{rfs@}} begins +with a @samp{/}.@refill + +@node opts Option, remopts Option, fs Option, Map Options +@comment node-name, next, previous, up +@subsubsection opts Option +@cindex Setting system mount options +@cindex Passing parameters to the mount system call +@cindex mount system call +@cindex mount system call flags +@cindex The mount system call +@cindex opts, mount option +@cindex Mount option; opts + +The options to pass to the mount system call. A leading @samp{-} is +silently ignored. The mount options supported generally correspond to +those used by @b{mount}(8) and are listed below. Some additional +pseudo-options are interpreted by @i{Amd} and are also listed. + +Unless specifically overridden, each of the system default mount options +applies. Any options not recognized are ignored. If no options list is +supplied the string @samp{rw,defaults} is used and all the system +default mount options apply. Options which are not applicable for a +particular operating system are silently ignored. For example, only 4.4BSD +is known to implement the @code{compress} and @code{spongy} options. + +@table @code + +@item acdirmax=@var{n} +@cindex Mount flags; acdirmax +Set the maximum directory attribute cache timeout to @var{n}. + +@item acdirmin=@var{n} +@cindex Mount flags; acdirmin +Set the minimum directory attribute cache timeout to @var{n}. + +@item acregmax=@var{n} +@cindex Mount flags; acregmax +Set the maximum file attribute cache timeout to @var{n}. + +@item acregmin=@var{n} +@cindex Mount flags; acregmin +Set the minimum file attribute cache timeout to @var{n}. + +@item actimeo=@var{n} +@cindex Mount flags; actimeo +Set the overall attribute cache timeout to @var{n}. + +@item auto +@cindex Mount flags; auto +@itemx ignore +@cindex Mount flags; ignore +Ignore this mount by @b{df}(1). + +@item cache +@cindex Mount flags; cache +Allow data to be cached from a remote server for this mount. + +@item compress +@cindex Mount flags; compress +Use NFS compression protocol. + +@item defperm +@cindex Mount flags; defperm +Ignore the permission mode bits, and default file permissions to 0555, +UID 0, and GID 0. Useful for CD-ROMs formatted as ISO-9660. + +@item dev +@cindex Mount flags; dev +Allow local special devices on this filesystem. + +@item dumbtimr +@cindex Mount flags; dumbtimr +(XXX: a dumb timer?) + +@item fsid +@cindex Mount flags; fsid +Set ID of filesystem. + +@item grpid +@cindex Mount flags; grpid +Use BSD directory group-id semantics. + +@item int +@cindex Mount flags; int +@itemx intr +@cindex Mount flags; intr +Allow keyboard interrupts on hard mounts. + +@item multi +@cindex Mount flags; multi +Perform multi-component lookup on files. + +@item maxgroups +@cindex Mount flags; maxgroups +Set the maximum number of groups to allow for this mount. + +@item nfsv3 +@cindex Mount flags; nfsv3 +Use NFS Version 3 for this mount. + +@item noac +@cindex Mount flags; noac +Turn off the attribute cache. + +@item noauto +@cindex Mount flags; noauto +(XXX: No automatic what?) + +@item nocache +@cindex Mount flags; nocache +Do not allow data to be cached from a remote server for this +mount. + +@item noconn +@cindex Mount flags; noconn +Don't make a connection on datagram transports. + +@item nocto +@cindex Mount flags; nocto +No close-to-open consistency. + +@item nodefperm +@cindex Mount flags; nodefperm +Do not ignore the permission mode bits. Useful for CD-ROMS formatted as +ISO-9660. + +@item nodev +@cindex Mount flags; nodev +@itemx nodevs +@cindex Mount flags; nodevs +Don't allow local special devices on this filesystem. + +@item noint +@cindex Mount flags; noint +Do not allow keyboard interrupts for this mount + +@item nosub +@cindex Mount flags; nosub +Disallow mounts beneath this mount. + +@item nosuid +@cindex Mount flags; nosuid +Don't allow set-uid or set-gid executables on this filesystem. + +@item noversion +@cindex Mount flags; noversion +Strip the extension @samp{;#} from the version string of files recorded +on an ISO-9660 CD-ROM. + +@item overlay +@cindex Mount flags; overlay +Overlay this mount on top of an existing mount, if any. + +@item pgthresh=@var{n} +@cindex Mount flags; pgthresh +Set the paging threshold to @var{n} kilobytes. + +@item port=@var{n} +@cindex Mount flags; port +Set the NFS port to @var{n}. + +@item posix +@cindex Mount flags; posix +Turn on POSIX static pathconf for mounts. + +@item proto=@var{s} +@cindex Mount flags; proto +Use transport protocol @var{s} for NFS (can be @code{"tcp"} or @code{"udp"}). + +@item quota +@cindex Mount flags; quota +Enable quota checking on this mount. + +@item rdonly +@cindex Mount flags; rdonly +@itemx ro +@cindex Mount flags; ro +Mount this filesystem readonly. + +@item resvport +@cindex Mount flags; resvport +Use a reserved port (smaller than 1024) for remote NFS mounts. Most +systems assume that, but some allow for mounts to occur on non-reserved +ports. This causes problems when such a system tries to NFS mount one +that requires reserved ports. It is recommended that this option always +be on. + +@item retrans=@i{n} +@cindex Mount flags; retrans +The number of NFS retransmits made before a user error is generated by a +@samp{soft} mounted filesystem, and before a @samp{hard} mounted +filesystem reports @samp{NFS server @dfn{yoyo} not responding still +trying}. + +@item retry +@cindex Mount flags; retry +Set the NFS retry counter. + +@item rrip +@cindex Mount flags; rrip +Uses the Rock Ridge Interchange Protocol (RRIP) extensions to ISO-9660. + +@item rsize=@var{n} +@cindex Mount flags; rsize +The NFS read packet size. You may need to set this if you are using +NFS/UDP through a gateway or a slow link. + +@item rw +@cindex Mount flags; rw +Allow reads and writes on this filesystem. + +@item soft +@cindex Mount flags; soft +Give up after @dfn{retrans} retransmissions. + +@item spongy +@cindex Mount flags; spongy +Like @samp{soft} for status requests, and @samp{hard} for data transfers. + +@item suid +@cindex Mount flags; suid +Allow set-uid programs on this mount. + +@item symttl +@cindex Mount flags; symttl +Turn of the symbolic link cache time-to-live. + +@item sync +@cindex Mount flags; sync +Perform synchronous filesystem operations on this mount. + +@item tcp +@cindex Mount flags; tcp +Use TCP/IP instead of UDP/IP, ignored if the NFS implementation does not +support TCP/IP mounts. + +@item timeo=@var{n} +@cindex Mount flags; timeo +The NFS timeout, in tenth-seconds, before a request is retransmitted. + +@item vers=@var{n} +@cindex Mount flags; vers + Use NFS protocol version number @var{n} (can be 2 or 3). + +@item wsize=@var{n} +@cindex Mount flags; wsize +The NFS write packet size. You may need to set this if you are using +NFS/UDP through a gateway or a slow link. + +@end table + +The following options are implemented by @i{Amd}, rather than being +passed to the kernel. + +@table @code + +@item nounmount +@cindex Mount flags; nounmount +Configures the mount so that its time-to-live will +never expire. This is also the default for some filesystem types. +@c +@c Implementation broken: + +@item ping=@var{n} +@cindex Mount flags; ping +The interval, in seconds, between keep-alive pings. When four +consecutive pings have failed the mount point is marked as hung. This +interval defaults to 30 seconds. If the ping interval is less than zero, +no pings are sent and the host is assumed to be always +up. By default, pings are not sent for an NFS/TCP mount. + +@item retry=@var{n} +@cindex Mount flags; retry=@var{n} +The number of times to retry the mount system call. + +@item utimeout=@var{n} +@cindex Mount flags; utimeout=@var{n} +The interval, in seconds, by which the mount's +time-to-live is extended after an unmount attempt +has failed. In fact the interval is extended before the unmount is +attempted to avoid thrashing. The default value is 120 seconds (two +minutes) or as set by the @code{-w} command line option. + +@end table + +@node remopts Option, sublink Option, opts Option, Map Options +@comment node-name, next, previous, up +@subsubsection remopts Option +@cindex Setting system mount options for non-local networks +@cindex remopts, mount option +@cindex Mount option; remopts + +This option has the same use as @code{$@{opts@}} but applies only when +the remote host is on a non-local network. For example, when using NFS +across a gateway it is often necessary to use smaller values for the +data read and write sizes. This can simply be done by specifying the +small values in @var{remopts}. When a non-local host is accessed, the +smaller sizes will automatically be used. + +@i{Amd} determines whether a host is local by examining the network +interface configuration at startup. Any interface changes made after +@i{Amd} has been started will not be noticed. The likely effect will +be that a host may incorrectly be declared non-local. + +Unless otherwise set, the value of @code{$@{remopts@}} is the same as +the value of @code{$@{opts@}}. + +@node sublink Option, type Option, remopts Option, Map Options +@comment node-name, next, previous, up +@subsubsection sublink Option +@cindex Setting the sublink option +@cindex sublink, mount option +@cindex Mount option; sublink + +The subdirectory within the mounted filesystem to which the reference +should point. This can be used to prevent duplicate mounts in cases +where multiple directories in the same mounted filesystem are used. + +@node type Option, , sublink Option, Map Options +@comment node-name, next, previous, up +@subsubsection type Option +@cindex Setting the filesystem type option +@cindex type, mount option +@cindex Mount option; type + +The filesystem type to be used. @xref{Filesystem Types}, for a full +description of each type.@refill + +@c ################################################################ +@node Amd Command Line Options, Filesystem Types, Mount Maps, Top +@comment node-name, next, previous, up +@chapter @i{Amd} Command Line Options +@cindex Command line options, Amd +@cindex Amd command line options +@cindex Overriding defaults on the command line + +Many of @i{Amd}'s parameters can be set from the command line. The +command line is also used to specify automount points and maps. + +The general format of a command line is + +@example +amd [@i{options}] [@{ @i{directory} @i{map-name} [-@i{map-options}] @} ...] +@end example + +For each directory and map-name given or specified in the +@file{amd.conf} file, @i{Amd} establishes an automount point. The +@dfn{map-options} may be any sequence of options or +selectors---@pxref{Location Format}. The @dfn{map-options} apply only +to @i{Amd}'s mount point. + +@samp{type:=toplvl;cache:=mapdefault;fs:=$@{map@}} is the default value for the +map options. Default options for a map are read from a special entry in +the map whose key is the string @samp{/defaults}. When default options +are given they are prepended to any options specified in the mount-map +locations as explained in @ref{Map Defaults}. + +The @dfn{options} are any combination of those listed below. + +Once the command line has been parsed, the automount points are mounted. +The mount points are created if they do not already exist, in which case they +will be removed when @i{Amd} exits. +Finally, @i{Amd} disassociates itself from its controlling terminal and +forks into the background. + +Note: Even if @i{Amd} has been built with @samp{-DDEBUG} (via +@code{configure --enable-debug}), it will still background itself and +disassociate itself from the controlling terminal. To use a debugger it +is necessary to specify @samp{-D nodaemon} on the command line. +However, even with all of this, mounts and unmounts are performed in the +background, and @i{Amd} will always fork before doing them. Therefore, +debugging what happens closely during un/mounts is more challenging. + +@emph{All} of @i{Amd}'s command options (save @code{-F} and @code{-T}) +can be specified in the @file{amd.conf} file. @xref{Amd Configuration +File}. If @i{Amd} is invoked without any command line options, it will +default to using the configuration file @file{/etc/amd.conf}, if one +exists. + +@menu +* -a Option:: Automount directory. +* -c Option:: Cache timeout interval. +* -d Option:: Domain name. +* -k Option:: Kernel architecture. +* -l Option:: Log file. +* -n Option:: Hostname normalization. +* -o Option:: Operating system version. +* -p Option:: Output process id. +* -r Option:: Restart existing mounts. +* -t Option:: Kernel RPC timeout. +* -v Option:: Version information. +* -w Option:: Wait interval after failed unmount. +* -x Option:: Log options. +* -y Option:: NIS domain. +* -C-Option:: Cluster name. +* -D-Option:: Debug flags. +* -F Option:: Amd configuration file. +* -H Option:: Show brief help. +* -O-Option:: Operating system name. +* -S Option:: Lock executable pages in memory. +* -T-Option:: Set tag for configuration file. +@end menu + +@c ---------------------------------------------------------------- +@node -a Option, -c Option, Amd Command Line Options, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-a} @var{directory} +@cindex Automount directory +@cindex Setting the default mount directory + +Specifies the default mount directory. This option changes the variable +@code{$@{autodir@}} which otherwise defaults to @file{/a}. For example, +some sites prefer @file{/amd} or @file{/n}. + +@example +amd -a /amd ... +@end example + +@c ---------------------------------------------------------------- +@node -c Option, -d Option, -a Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-c} @var{cache-interval} +@cindex Cache interval +@cindex Interval before a filesystem times out +@cindex Setting the interval before a filesystem times out +@cindex Changing the interval before a filesystem times out + +Selects the period, in seconds, for which a name is cached by @i{Amd}. +If no reference is made to the volume in this period, @i{Amd} discards +the volume name to filesystem mapping. + +Once the last reference to a filesystem has been removed, @i{Amd} +attempts to unmount the filesystem. If the unmount fails the interval +is extended by a further period as specified by the @samp{-w} command +line option or by the @samp{utimeout} mount option. + +The default @dfn{cache-interval} is 300 seconds (five minutes). + +@c ---------------------------------------------------------------- +@node -d Option, -k Option, -c Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-d} @var{domain} +@cindex Domain name +@cindex Setting the local domain name +@cindex Overriding the local domain name + +Specifies the host's domain. This sets the internal variable +@code{$@{domain@}} and affects the @code{$@{hostd@}} variable. + +If this option is not specified and the hostname already contains the +local domain then that is used, otherwise the default value of +@code{$@{domain@}} is @samp{unknown.domain}. + +For example, if the local domain was @samp{doc.ic.ac.uk}, @i{Amd} could +be started as follows: + +@example +amd -d doc.ic.ac.uk ... +@end example + +@c ---------------------------------------------------------------- +@node -k Option, -l Option, -d Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-k} @var{kernel-architecture} +@cindex Setting the Kernel architecture + +Specifies the kernel architecture of the system. This is usually the +output of @samp{uname -m} (the ``machine'' value gotten from +@b{uname}(2)). If the @b{uname}(2) system call is not available, the +value of @code{$@{karch@}} defaults to that of @code{$@{arch@}}. + +The only effect of this option is to set the variable @code{$@{karch@}}. + +This option would be used as follows: + +@example +amd -k `arch -k` ... +@end example + +@c ---------------------------------------------------------------- +@node -l Option, -n Option, -k Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-l} @var{log-option} +@cindex Log filename +@cindex Setting the log file +@cindex Using syslog to log errors +@cindex syslog + +Selects the form of logging to be made. Several special @dfn{log-options} +are recognized. + +@enumerate +@item +If @dfn{log-option} is the string @samp{syslog}, @i{Amd} will use the +@b{syslog}(3) mechanism. If your system supports syslog facilities, then +the default facility used is @samp{LOG_DAEMON}. + +@item +@cindex syslog facility; specifying an alternate +When using syslog, if you wish to change the facility, append its name +to the log option name, delimited by a single colon. For example, if +@dfn{log-options} is the string @samp{syslog:local7} then @b{Amd} will +log messages via @b{syslog}(3) using the @samp{LOG_LOCAL7} facility. If +the facility name specified is not recognized, @i{Amd} will default to +@samp{LOG_DAEMON}. Note: while you can use any syslog facility +available on your system, it is generally a bad idea to use those +reserved for other services such as @samp{kern}, @samp{lpr}, +@samp{cron}, etc. + +@item +If @dfn{log-option} is the string @samp{/dev/stderr}, @i{Amd} will use +standard error, which is also the default target for log messages. To +implement this, @i{Amd} simulates the effect of the @samp{/dev/fd} +driver. +@end enumerate + +Any other string is taken as a filename to use for logging. Log +messages are appended to the file if it already exists, otherwise a new +file is created. The file is opened once and then held open, rather +than being re-opened for each message. + +Normally, when long-running daemons hold an open file descriptor on a +log file, it is impossible to ``rotate'' the log file and compress older +logs on a daily basis. The daemon needs to be told to discard (via +@b{close}(2)) its file handle, and re-open the log file. This is done +using @code{amq -l} @i{log-option}. @xref{Amq -l option}. + +If the @samp{syslog} option is specified but the system does not support +syslog or if the named file cannot be opened or created, @i{Amd} will +use standard error. Error messages generated before @i{Amd} has +finished parsing the command line are printed on standard error. + +Since @i{Amd} tends to generate a lot of logging information (especially +if debugging was turned on), and due to it being an important program +running on the system, it is usually best to log to a separate disk +file. In that case @i{Amd} would be started as follows: + +@example +amd -l /var/log/amd ... +@end example + +@c ---------------------------------------------------------------- +@node -n Option, -o Option, -l Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-n} +@cindex Hostname normalization +@cindex Aliased hostnames +@cindex Resolving aliased hostnames +@cindex Normalizing hostnames + +Normalizes the remote hostname before using it. Normalization is done +by replacing the value of @code{$@{rhost@}} with the (generally fully +qualified) primary name returned by a hostname lookup. + +This option should be used if several names are used to refer to a +single host in a mount map. + +@c ---------------------------------------------------------------- +@node -o Option, -p Option, -n Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-o} @var{op-sys-ver} +@cindex Operating System version +@cindex Setting the Operating System version + +Override the compiled-in version number of the operating system, with +@var{op-sys-ver}. Useful when the built-in version is not desired for +backward compatibility reasons. For example, if the built-in version is +@samp{2.5.1}, you can override it to @samp{5.5.1}, and use older maps +that were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node -p Option, -r Option, -o Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-p} +@cindex Process id +@cindex Displaying the process id +@cindex process id of Amd daemon +@cindex pid file, creating with -p option +@cindex Creating a pid file + +Causes @i{Amd}'s process id to be printed on standard output. +This can be redirected to a suitable file for use with kill: + +@example +amd -p > /var/run/amd.pid ... +@end example + +This option only has an affect if @i{Amd} is running in daemon mode. +If @i{Amd} is started with the @code{-D nodaemon} debug flag, this +option is ignored. + +@c ---------------------------------------------------------------- +@node -r Option, -t Option, -p Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-r} +@cindex Restarting existing mounts +@cindex Picking up existing mounts + +Tells @i{Amd} to restart existing mounts (@pxref{Inheritance Filesystem}). +@c @dfn{This option will be made the default in the next release.} + +@c ---------------------------------------------------------------- +@node -t Option, -v Option, -r Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-t} @var{timeout.retransmit} +@cindex Setting Amd's RPC parameters + +Specifies the RPC @dfn{timeout} and @dfn{retransmit} intervals used by +the kernel to communicate to @i{Amd}. These are used to set the +@samp{timeo} and @samp{retrans} mount options. + +@i{Amd} relies on the kernel RPC retransmit mechanism to trigger mount +retries. The value of this parameter changes the retry interval. Too +long an interval gives poor interactive response, too short an interval +causes excessive retries. + +@c ---------------------------------------------------------------- +@node -v Option, -w Option, -t Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-v} +@cindex Version information +@cindex Discovering version information +@cindex How to discover your version of Amd + +Print version information on standard error and then exit. The output +is of the form: + +@example +Copyright (c) 1997-1998 Erez Zadok +Copyright (c) 1990 Jan-Simon Pendry +Copyright (c) 1990 Imperial College of Science, Technology & Medicine +Copyright (c) 1990 The Regents of the University of California. +am-utils version 6.0a15 (build 61). +Built by ezk@@cs.columbia.edu on date Wed Oct 22 15:21:03 EDT 1997. +cpu=sparc (big-endian), arch=sun4, karch=sun4u. +full_os=solaris2.5.1, os=sos5, osver=5.5.1, vendor=sun. +Map support for: root, passwd, union, nisplus, nis, ndbm, file, error. +AMFS: nfs, link, nfsx, nfsl, host, linkx, program, union, inherit, + ufs, lofs, hsfs, pcfs, auto, direct, toplvl, error. +FS: autofs, cachefs, cdfs, lofs, nfs, nfs3, pcfs, tfs, tmpfs, ufs. +Network 1: wire="mcl-lab-net.cs.columbia.edu" (netnumber=128.59.13). +Network 2: wire="14-net.cs.columbia.edu" (netnumber=128.59.14). +Network 3: wire="old-net.cs.columbia.edu" (netnumber=128.59.16). +@end example + +The information includes the version number, number of times @i{Amd} was +compiled on the local system, release date and name of the release. +Following come the cpu type, byte ordering, and the architecture and +kernel architecture as @code{$@{arch@}} and @code{$@{karch@}}, +respectively. The next line lists the full name of the system, the +variables @code{$@{os@}} and @code{$@{osver@}}, and the vendor's +name. @xref{Supported Platforms}. + +Then come a list of map types supported, filesystems internally +supported by @i{Amd} (AMFS), and generic filesystems available (FS). +Finally all known networks (if any) of this host are listed by name +and number. They are available via the variables +@code{$@{wire@}} or @code{$@{network@}}, and +@code{$@{netnumber@}} (@pxref{Selectors}) or the @samp{in_network} +selector function (@pxref{in_network Selector Function}). + +@c ---------------------------------------------------------------- +@node -w Option, -x Option, -v Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-w} @var{wait-timeout} +@cindex Setting the interval between unmount attempts +@cindex unmount attempt backoff interval + +Selects the interval in seconds between unmount attempts after the +initial time-to-live has expired. + +This defaults to 120 seconds (two minutes). + +@c ---------------------------------------------------------------- +@node -x Option, -y Option, -w Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-x} @var{opts} +@cindex Log message selection +@cindex Selecting specific log messages +@cindex How to select log messages +@cindex syslog priorities + +Specifies the type and verbosity of log messages. @dfn{opts} is +a comma separated list selected from the following options: + +@table @code +@item fatal +Fatal errors +@item error +Non-fatal errors +@item user +Non-fatal user errors +@item warn +Recoverable errors +@item warning +Alias for @code{warn} +@item info +Information messages +@item map +Mount map usage +@item stats +Additional statistics +@item all +All of the above +@end table + +Initially a set of default logging flags is enabled. This is as if +@samp{-x all,nomap,nostats} had been selected. The command line is +parsed and logging is controlled by the @code{-x} option. The very first +set of logging flags is saved and can not be subsequently disabled using +@i{Amq}. This default set of options is useful for general production +use.@refill + +The @samp{info} messages include details of what is mounted and +unmounted and when filesystems have timed out. If you want to have the +default set of messages without the @samp{info} messages then you simply +need @samp{-x noinfo}. The messages given by @samp{user} relate to +errors in the mount maps, so these are useful when new maps are +installed. The following table lists the syslog priorities used for each +of the message types.@refill + +@table @code +@item fatal +@samp{LOG_CRIT} +@item error +@samp{LOG_ERR} +@item user +@samp{LOG_WARNING} +@item warning +@samp{LOG_WARNING} +@item info +@samp{LOG_INFO} +@item debug +@samp{LOG_DEBUG} +@item map +@samp{LOG_DEBUG} +@item stats +@samp{LOG_INFO} +@end table + + +The options can be prefixed by the string @samp{no} to indicate +that this option should be turned off. For example, to obtain all +but @samp{info} messages the option @samp{-x all,noinfo} would be used. + +If @i{Amd} was built with debugging enabled the @code{debug} option is +automatically enabled regardless of the command line options. + +@c ---------------------------------------------------------------- +@node -y Option, -C-Option, -x Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-y} @var{NIS-domain} +@cindex NIS (YP) domain name +@cindex Overriding the NIS (YP) domain name +@cindex Setting the NIS (YP) domain name +@cindex YP domain name + +Selects an alternate NIS domain. This is useful for debugging and +cross-domain shared mounting. If this flag is specified, @i{Amd} +immediately attempts to bind to a server for this domain. +@c @i{Amd} refers to NIS maps when it starts, unless the @code{-m} option +@c is specified, and whenever required in a mount map. + +@c ---------------------------------------------------------------- +@node -C-Option, -D-Option, -y Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-C} @var{cluster-name} +@cindex Cluster names +@cindex Setting the cluster name + +Specifies the name of the cluster of which the local machine is a member. +The only effect is to set the variable @code{$@{cluster@}}. +The @dfn{cluster-name} is will usually obtained by running another command which uses +a database to map the local hostname into a cluster name. +@code{$@{cluster@}} can then be used as a selector to restrict mounting of +replicated data. +If this option is not given, @code{$@{cluster@}} has the same value as @code{$@{domain@}}. +This would be used as follows: + +@example +amd -C `clustername` ... +@end example + +@c ---------------------------------------------------------------- +@node -D-Option, -F Option, -C-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-D} @var{opts} +@cindex Debug options +@cindex Setting debug flags + +Controls the verbosity and coverage of the debugging trace; @dfn{opts} +is a comma separated list of debugging options. The @code{-D} option is +only available if @i{Amd} was compiled with @samp{-DDEBUG}, or +configured with @code{configure --enable-debug}. The memory debugging +facilities (@samp{mem}) are only available if @i{Amd} was compiled with +@samp{-DDEBUG_MEM} (in addition to @samp{-DDEBUG}), or configured with +@code{configure --enable-debug=mem}. + +The most common options to use are @samp{-D trace} and @samp{-D test} +(which turns on all the useful debug options). As usual, every option +can be prefixed with @samp{no} to turn it off. + +@table @code +@item all +all options +@item amq +register for amq +@item daemon +enter daemon mode +@item fork +fork server +@item full +program trace +@item info +@cindex debugging hesiod resolver service +@cindex Hesiod: turning on RES_DEBUG +info service specific debugging (hesiod, nis, etc.) In the case of +hesiod maps, turns on the hesiod RES_DEBUG internal debugging option. +@item mem +trace memory allocations +@item mtab +use local @file{./mtab} file +@item str +debug string munging +@item test +full debug but no daemon +@item trace +protocol trace +@end table + +You may also refer to the program source for a more detailed explanation +of the available options. + +@c ---------------------------------------------------------------- +@node -F Option, -H Option, -D-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-F} @var{conf-file} +@cindex Amd configuration file; specifying name +@cindex Amd configuration file +@cindex amd.conf file + +Specify an @i{Amd} configuration file @var{conf-file} to use. For a +description of the format and syntax, @pxref{Amd Configuration File}. +This configuration file is used to specify any options in lieu of typing +many of them on the command line. The @file{amd.conf} file includes +directives for every command line option @i{Amd} has, and many more that +are only available via the configuration file facility. The +configuration file specified by this option is processed after all other +options had been processed, regardless of the actual location of this +option on the command line. + +@c ---------------------------------------------------------------- +@node -H Option, -O-Option, -F Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-H} +@cindex Displaying brief help +@cindex Help; showing from Amd + +Print a brief help and usage string. + +@c ---------------------------------------------------------------- +@node -O-Option, -S Option, -H Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-O} @var{op-sys-name} +@cindex Operating System name +@cindex Setting the Operating System name + +Override the compiled-in name of the operating system, with +@var{op-sys-name}. Useful when the built-in name is not desired for +backward compatibility reasons. For example, if the build in name is +@samp{sunos5}, you can override it to the old name @samp{sos5}, and use +older maps which were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node -S Option, -T-Option, -O-Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-S} +@cindex plock; using +@cindex locking executable pages in memory + +Do @emph{not} lock the running executable pages of @i{Amd} into memory. +To improve @i{Amd}'s performance, systems that support the @b{plock}(3) +call lock the @i{Amd} process into memory. This way there is less +chance the operating system will schedule, page out, and swap the +@i{Amd} process as needed. This tends to improve @i{Amd}'s performance, +at the cost of reserving the memory used by the @i{Amd} process (making +it unavailable for other processes). If this behavior is not desired, +use the @code{-S} option. + +@c ---------------------------------------------------------------- +@node -T-Option, , -S Option, Amd Command Line Options +@comment node-name, next, previous, up +@section @code{-T} @var{tag} +@cindex Tags for Amd configuration file +@cindex Configuration file; tags + +Specify a tag to use with @file{amd.conf}. All map entries tagged with +@var{tag} will be processed. Map entries that are not tagged are always +processed. Map entries that are tagged with a tag other than @var{tag} +will not be processed. + +@c ################################################################ +@node Filesystem Types, Amd Configuration File, Amd Command Line Options, Top +@comment node-name, next, previous, up +@chapter Filesystem Types +@cindex Filesystem types +@cindex Mount types +@cindex Types of filesystem + +To mount a volume, @i{Amd} must be told the type of filesystem to be +used. Each filesystem type typically requires additional information +such as the fileserver name for NFS. + +From the point of view of @i{Amd}, a @dfn{filesystem} is anything that +can resolve an incoming name lookup. An important feature is support +for multiple filesystem types. Some of these filesystems are +implemented in the local kernel and some on remote fileservers, whilst +the others are implemented internally by @i{Amd}.@refill + +The two common filesystem types are UFS and NFS. Four other user +accessible filesystems (@samp{link}, @samp{program}, @samp{auto} and +@samp{direct}) are also implemented internally by @i{Amd} and these are +described below. There are two additional filesystem types internal to +@i{Amd} which are not directly accessible to the user (@samp{inherit} +and @samp{error}). Their use is described since they may still have an +effect visible to the user.@refill + +@menu +* Network Filesystem:: A single NFS filesystem. +* Network Host Filesystem:: NFS mount a host's entire export tree. +* Network Filesystem Group:: An atomic group of NFS filesystems. +* Unix Filesystem:: Native disk filesystem. +* Caching Filesystem:: Caching from remote server filesystem. +* CD-ROM Filesystem:: ISO9660 CD ROM. +* Loopback Filesystem:: Local loopback-mount filesystem. +* Memory/RAM Filesystem:: A memory or RAM-based filesystem. +* Null Filesystem:: 4.4BSD's loopback-mount filesystem. +* Floppy Filesystem:: MS-DOS Floppy filesystem. +* Translucent Filesystem:: The directory merging filesystem. +* Shared Memory+Swap Filesystem:: Sun's tmpfs filesystem. +* User ID Mapping Filesystem:: 4.4BSD's umapfs filesystem. +* Program Filesystem:: Generic Program mounts. +* Symbolic Link Filesystem:: Local link. +* Symbolic Link Filesystem II:: Local link referencing existing filesystem. +* NFS-Link Filesystem:: Link if path exists, NFS otherwise. +* Automount Filesystem:: +* Direct Automount Filesystem:: +* Union Filesystem:: +* Error Filesystem:: +* Top-level Filesystem:: +* Autofs Filesystem:: Sun's kernel-based automounter filesystem. +* Root Filesystem:: +* Inheritance Filesystem:: +@end menu + +@c ---------------------------------------------------------------- +@node Network Filesystem, Network Host Filesystem, Filesystem Types, Filesystem Types +@comment node-name, next, previous, up +@section Network Filesystem (@samp{nfs}) +@cindex NFS +@cindex Mounting an NFS filesystem +@cindex How to mount and NFS filesystem +@cindex nfs, filesystem type +@cindex Filesystem type; nfs + +The @dfn{nfs} (@samp{type:=nfs}) filesystem type provides access to Sun's NFS. + +@noindent +The following options must be specified: + +@table @code +@cindex rhost, mount option +@cindex Mount option; rhost +@item rhost +the remote fileserver. This must be an entry in the hosts database. IP +addresses are not accepted. The default value is taken +from the local host name (@code{$@{host@}}) if no other value is +specified. + +@cindex rfs, mount option +@cindex Mount option; rfs +@item rfs +the remote filesystem. +If no value is specified for this option, an internal default of +@code{$@{path@}} is used. +@end table + +NFS mounts require a two stage process. First, the @dfn{file handle} of +the remote file system must be obtained from the server. Then a mount +system call must be done on the local system. @i{Amd} keeps a cache +of file handles for remote file systems. The cache entries have a +lifetime of a few minutes. + +If a required file handle is not in the cache, @i{Amd} sends a request +to the remote server to obtain it. @i{Amd} @dfn{does not} wait for +a response; it notes that one of the locations needs retrying, but +continues with any remaining locations. When the file handle becomes +available, and assuming none of the other locations was successfully +mounted, @i{Amd} will retry the mount. This mechanism allows several +NFS filesystems to be mounted in parallel. +@c @footnote{The mechanism +@c is general, however NFS is the only filesystem +@c for which the required hooks have been written.} +The first one which responds with a valid file handle will be used. + +@noindent +An NFS entry might be: + +@example +jsp host!=charm;type:=nfs;rhost:=charm;rfs:=/home/charm;sublink:=jsp +@end example + +The mount system call and any unmount attempts are always done +in a new task to avoid the possibility of blocking @i{Amd}. + +@c ---------------------------------------------------------------- +@node Network Host Filesystem, Network Filesystem Group, Network Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Network Host Filesystem (@samp{host}) +@cindex Network host filesystem +@cindex Mounting entire export trees +@cindex How to mount all NFS exported filesystems +@cindex host, filesystem type +@cindex Filesystem type; host + +@c NOTE: the current implementation of the @dfn{host} filesystem type +@c sometimes fails to maintain a consistent view of the remote mount tree. +@c This happens when the mount times out and only some of the remote mounts +@c are successfully unmounted. To prevent this from occurring, use the +@c @samp{nounmount} mount option. + +The @dfn{host} (@samp{type:=host}) filesystem allows access to the entire export tree of an +NFS server. The implementation is layered above the @samp{nfs} +implementation so keep-alives work in the same way. The only option +which needs to be specified is @samp{rhost} which is the name of the +fileserver to mount. + +The @samp{host} filesystem type works by querying the mount daemon on +the given fileserver to obtain its export list. @i{Amd} then obtains +filehandles for each of the exported filesystems. Any errors at this +stage cause that particular filesystem to be ignored. Finally each +filesystem is mounted. Again, errors are logged but ignored. One +common reason for mounts to fail is that the mount point does not exist. +Although @i{Amd} attempts to automatically create the mount point, it +may be on a remote filesystem to which @i{Amd} does not have write +permission. + +When an attempt to unmount a @samp{host} filesystem mount fails, @i{Amd} +remounts any filesystems which had successfully been unmounted. To do +this @i{Amd} queries the mount daemon again and obtains a fresh copy of +the export list. @i{Amd} then tries to mount any exported filesystems +which are not currently mounted. + +Sun's automounter provides a special @samp{-hosts} map. To achieve the +same effect with @i{Amd} requires two steps. First a mount map must +be created as follows: + +@example +* type:=host;rhost:=$@{key@};fs:=$@{autodir@}/$@{rhost@}/root +@end example + +@noindent +and then start @i{Amd} with the following command + +@example +amd /net net.map +@end example + +@noindent +where @samp{net.map} is the name of map described above. Note that the +value of @code{$@{fs@}} is overridden in the map. This is done to avoid +a clash between the mount tree and any other filesystem already mounted +from the same fileserver. + +If different mount options are needed for different hosts then +additional entries can be added to the map, for example + +@example +host2 opts:=ro,nosuid,soft +@end example + +@noindent +would soft mount @samp{host2} read-only. + +@c ---------------------------------------------------------------- +@node Network Filesystem Group, Unix Filesystem, Network Host Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Network Filesystem Group (@samp{nfsx}) +@cindex Network filesystem group +@cindex Atomic NFS mounts +@cindex Mounting an atomic group of NFS filesystems +@cindex How to mount an atomic group of NFS filesystems +@cindex nfsx, filesystem type +@cindex Filesystem type; nfsx + +The @dfn{nfsx} (@samp{type:=nfsx}) filesystem allows a group of filesystems to be mounted +from a single NFS server. The implementation is layered above the +@samp{nfs} implementation so keep-alives work in the same way. + +The options are the same as for the @samp{nfs} filesystem with one +difference. + +@noindent +The following options must be specified: + +@table @code +@item rhost +the remote fileserver. This must be an entry in the hosts database. IP +addresses are not accepted. The default value is taken from the local +host name (@code{$@{host@}}) if no other value is specified. + +@item rfs +as a list of filesystems to mount. The list is in the form of a comma +separated strings. +@end table + +@noindent +For example: + +@example +pub type:=nfsx;rhost:=gould;\ + rfs:=/public,/,graphics,usenet;fs:=$@{autodir@}/$@{rhost@}/root +@end example + +The first string defines the root of the tree, and is applied as a +prefix to the remaining members of the list which define the individual +filesystems. The first string is @emph{not} used as a filesystem name. +A parallel operation is used to determine the local mount points to +ensure a consistent layout of a tree of mounts. + +Here, the @emph{three} filesystems, @samp{/public}, +@samp{/public/graphics} and @samp{/public/usenet}, would be mounted.@refill + +A local mount point, @code{$@{fs@}}, @emph{must} be specified. The +default local mount point will not work correctly in the general case. +A suggestion is to use @samp{fs:=$@{autodir@}/$@{rhost@}/root}.@refill + +@c ---------------------------------------------------------------- +@node Unix Filesystem, Caching Filesystem, Network Filesystem Group, Filesystem Types +@comment node-name, next, previous, up +@section Unix Filesystem (@samp{ufs}, @samp{xfs}, or @samp{efs}) +@cindex Unix filesystem +@cindex UFS +@cindex XFS +@cindex EFS +@cindex Mounting a UFS filesystem +@cindex Mounting a local disk +@cindex How to mount a UFS filesystems +@cindex How to mount a local disk +@cindex Disk filesystems +@cindex ufs, filesystem type +@cindex Filesystem type; ufs +@cindex xfs, filesystem type +@cindex Filesystem type; xfs +@cindex efs, filesystem type +@cindex Filesystem type; efs + +The @dfn{ufs} (@samp{type:=ufs}) filesystem type provides access to the system's standard +disk filesystem---usually a derivative of the Berkeley Fast Filesystem. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A UFS entry might be: + +@example +jsp host==charm;type:=ufs;dev:=/dev/sd0d;sublink:=jsp +@end example + +UFS is the default Unix disk-based file system, which Am-utils picks up +during the autoconfiguration phase. Some systems have more than one +type, such as IRIX, that comes with EFS (Extent File System) and XFS +(Extended File System). In those cases, you may explicitly set the file +system type, by using entries such: + +@example +ez1 type:=efs;dev:=/dev/xd0a +ez2 type:=xfs;dev:=/dev/sd3c +@end example + +@c ---------------------------------------------------------------- +@node Caching Filesystem, CD-ROM Filesystem, Unix Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Caching Filesystem (@samp{cachefs}) +@cindex Caching Filesystem +@cindex cachefs, filesystem type +@cindex Filesystem type; cachefs + +The @dfn{cachefs} (@samp{type:=cachefs}) filesystem caches files from +one location onto another, presumably providing faster access. It is +particularly useful to cache from a larger and remote (slower) NFS +partition to a smaller and local (faster) UFS directory. + +@noindent +The following options must be specified: + +@table @code +@cindex cachedir, mount option +@cindex Mount option; cachedir +@item cachedir +the directory where the cache is stored. +@item rfs +the path name to the ``back file system'' to be cached from. +@item fs +the ``front file system'' mount point to the cached files, where @i{Amd} +will set a symbolic link pointing to. +@end table + +A CacheFS entry for, say, the @file{/import} @i{Amd} mount point, might +be: + +@example +copt type:=cachefs;cachedir:=/cache;rfs:=/import/opt;fs:=/n/import/copt +@end example + +Access to the pathname @file{/import/copt} will follow a symbolic link +to @file{/n/import/copt}. The latter is the mount point for a caching +file system, that caches from @file{/import/opt} to @file{/cache}. + +@b{Caveats}: +@enumerate +@item This file system is currently only implemented for Solaris 2.x! +@item Before being used for the first time, the cache directory @i{must} be +initialized with @samp{cfsadmin -c @var{cachedir}}. See the manual page for +@b{cfsadmin}(1M) for more information. +@item The ``back file system'' mounted must be a complete file system, not +a subdirectory thereof; otherwise you will get an error ``Invalid Argument''. +@item If @i{Amd} aborts abnormally, the state of the cache may be +inconsistent, requiring running the command @file{fsck -F cachefs +@var{cachedir}}. Otherwise you will get the error ``No Space Left on Device''. +@end enumerate + +@c ---------------------------------------------------------------- +@node CD-ROM Filesystem, Loopback Filesystem, Caching Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section CD-ROM Filesystem (@samp{cdfs}) +@cindex CD-ROM Filesystem +@cindex cdfs, filesystem type +@cindex Filesystem type; cdfs + +The @dfn{cdfs} (@samp{type:=cdfs}) filesystem mounts a CD-ROM with an +ISO9660 format filesystem on it. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A cdfs entry might be: + +@example +cdfs os==sunos4;type:=cdfs;dev:=/dev/sr0 \ + os==sunos5;type:=cdfs;dev:=/dev/dsk/c0t6d0s2 +@end example + +@c ---------------------------------------------------------------- +@node Loopback Filesystem, Memory/RAM Filesystem, CD-ROM Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Loopback Filesystem (@samp{lofs}) +@cindex Loopback Filesystem +@cindex lofs, filesystem type +@cindex Filesystem type; lofs + +The @dfn{lofs} (@samp{type:=lofs}) filesystem is also called the +loopback filesystem. It mounts a local directory on another, thus +providing mount-time binding to another location (unlike symbolic +links). + +The loopback filesystem is particularly useful within the context of a +chroot-ed directory (via @b{chroot}(2)), to provide access to +directories otherwise inaccessible. + +@noindent +The following option must be specified: + +@table @code +@cindex rfs, mount option +@cindex Mount option; rfs +@item rfs +the pathname to be mounted on top of @code{$@{fs@}}. +@end table + +Usually, the FTP server runs in a chroot-ed environment, for security +reasons. In this example, lofs is used to provide a subdirectory within +a user's home directory, also available for public ftp. + +@example +lofs type:=lofs;rfs:=/home/ezk/myftpdir;fs:=/usr/ftp/pub/ezk +@end example + +@c ---------------------------------------------------------------- +@node Memory/RAM Filesystem, Null Filesystem, Loopback Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Memory/RAM Filesystem (@samp{mfs}) +@cindex Memory/RAM Filesystem +@cindex mfs, filesystem type +@cindex Filesystem type; mfs + +The @dfn{mfs} (@samp{type:=mfs}) filesystem is available in 4.4BSD, +Linux, and other systems. It creates a filesystem in a portion of the +system's memory, thus providing very fast file (volatile) access. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Null Filesystem, Floppy Filesystem, Memory/RAM Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Null Filesystem (@samp{nullfs}) +@cindex Null Filesystem +@cindex nullfs, filesystem type +@cindex Filesystem type; nullfs + +The @dfn{nullfs} (@samp{type:=nullfs}) filesystem is available from 4.4BSD, +and is very similar to the loopback filesystem, @dfn{lofs}. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Floppy Filesystem, Translucent Filesystem, Null Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Floppy Filesystem (@samp{pcfs}) +@cindex Floppy Filesystem +@cindex pcfs, filesystem type +@cindex Filesystem type; pcfs + +The @dfn{pcfs} (@samp{type:=pcfs}) filesystem mounts a floppy previously +formatted for the MS-DOS format. + +@noindent +The following option must be specified: + +@table @code +@cindex dev, mount option +@cindex Mount option; dev +@item dev +the block special device to be mounted. +@end table + +A pcfs entry might be: + +@example +pcfs os==sunos4;type:=pcfs;dev:=/dev/fd0 \ + os==sunos5;type:=pcfs;dev:=/dev/diskette +@end example + +@c ---------------------------------------------------------------- +@node Translucent Filesystem, Shared Memory+Swap Filesystem, Floppy Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Translucent Filesystem (@samp{tfs}) +@cindex Translucent Filesystem +@cindex tfs, filesystem type +@cindex Filesystem type; tfs + +The @dfn{tfs} (@samp{type:=tfs}) filesystem is an older version of the +4.4BSD @dfn{unionfs}. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Shared Memory+Swap Filesystem, User ID Mapping Filesystem, Translucent Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Shared Memory+Swap Filesystem (@samp{tmpfs}) +@cindex Shared Memory and Swap Filesystem +@cindex tmpfs, filesystem type +@cindex Filesystem type; tmpfs + +The @dfn{tmpfs} (@samp{type:=tmpfs}) filesystem shares memory between a +the swap device and the rest of the system. It is generally used to +provide a fast access @file{/tmp} directory, one that uses memory that +is otherwise unused. This filesystem is available in SunOS 4.x and 5.x. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node User ID Mapping Filesystem, Program Filesystem, Shared Memory+Swap Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section User ID Mapping Filesystem (@samp{umapfs}) +@cindex User ID Mapping Filesystem +@cindex umapfs, filesystem type +@cindex Filesystem type; umapfs + +The @dfn{umapfs} (@samp{type:=umapfs}) filesystem maps User IDs of file +ownership, and is available from 4.4BSD. + +XXX: THIS FILESYSTEM IS NOT IMPLEMENTED YET! + +@c ---------------------------------------------------------------- +@node Program Filesystem, Symbolic Link Filesystem, User ID Mapping Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Program Filesystem (@samp{program}) +@cindex Program filesystem +@cindex Mount a filesystem under program control +@cindex program, filesystem type +@cindex Filesystem type; program + +The @dfn{program} (@samp{type:=program}) filesystem type allows a program to be run whenever a +mount or unmount is required. This allows easy addition of support for +other filesystem types, such as MIT's Remote Virtual Disk (RVD) +which has a programmatic interface via the commands +@samp{rvdmount} and @samp{rvdunmount}. + +@noindent +The following options must be specified: + +@table @code +@cindex mount, mount option +@cindex Mount option; mount +@item mount +the program which will perform the mount. + +@cindex unmount, mount option +@cindex Mount option; unmount +@item unmount +the program which will perform the unmount. +@end table + +The exit code from these two programs is interpreted as a Unix error +code. As usual, exit code zero indicates success. To execute the +program @i{Amd} splits the string on whitespace to create an array of +substrings. Single quotes @samp{'} can be used to quote whitespace +if that is required in an argument. There is no way to escape or change +the quote character. + +To run the program @samp{rvdmount} with a host name and filesystem as +arguments would be specified by @samp{mount:="/etc/rvdmount rvdmount +fserver $@{path@}"}. + +The first element in the array is taken as the pathname of the program +to execute. The other members of the array form the argument vector to +be passed to the program, @dfn{including argument zero}. This means +that the split string must have at least two elements. The program is +directly executed by @i{Amd}, not via a shell. This means that scripts +must begin with a @code{#!} interpreter specification. + +If a filesystem type is to be heavily used, it may be worthwhile adding +a new filesystem type into @i{Amd}, but for most uses the program +filesystem should suffice. + +When the program is run, standard input and standard error are inherited +from the current values used by @i{Amd}. Standard output is a +duplicate of standard error. The value specified with the @code{-l} +command line option has no effect on standard error. + +@c ---------------------------------------------------------------- +@node Symbolic Link Filesystem, Symbolic Link Filesystem II, Program Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Symbolic Link Filesystem (@samp{link}) +@cindex Symbolic link filesystem +@cindex Referencing part of the local name space +@cindex Mounting part of the local name space +@cindex How to reference part of the local name space +@cindex link, filesystem type +@cindex symlink, link filesystem type +@cindex Filesystem type; link + +Each filesystem type creates a symbolic link to point from the volume +name to the physical mount point. The @samp{link} filesystem does the +same without any other side effects. This allows any part of the +machines name space to be accessed via @i{Amd}. + +One common use for the symlink filesystem is @file{/homes} which can be +made to contain an entry for each user which points to their +(auto-mounted) home directory. Although this may seem rather expensive, +it provides a great deal of administrative flexibility. + +@noindent +The following option must be defined: + +@table @code +@item fs +The value of @var{fs} option specifies the destination of the link, as +modified by the @var{sublink} option. If @var{sublink} is non-null, it +is appended to @code{$@{fs@}}@code{/} and the resulting string is used +as the target. +@end table + +The @samp{link} filesystem can be thought of as identical to the +@samp{ufs} filesystem but without actually mounting anything. + +An example entry might be: + +@example +jsp host==charm;type:=link;fs:=/home/charm;sublink:=jsp +@end example +which would return a symbolic link pointing to @file{/home/charm/jsp}. + +@c ---------------------------------------------------------------- +@node Symbolic Link Filesystem II, NFS-Link Filesystem, Symbolic Link Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Symbolic Link Filesystem II (@samp{linkx}) +@cindex Symbolic link filesystem II +@cindex Referencing an existing part of the local name space +@cindex Mounting an existing part of the local name space +@cindex How to reference an existing part of the local name space +@cindex linkx, filesystem type +@cindex symlink, linkx filesystem type +@cindex Filesystem type; linkx + +The @dfn{linkx} (@samp{type:=linkx}) filesystem type is identical to @samp{link} with the +exception that the target of the link must exist. Existence is checked +with the @b{lstat}(2) system call. + +The @samp{linkx} filesystem type is particularly useful for wildcard map +entries. In this case, a list of possible targets can be given and +@i{Amd} will choose the first one which exists on the local machine. + +@c ---------------------------------------------------------------- +@node NFS-Link Filesystem, Automount Filesystem, Symbolic Link Filesystem II, Filesystem Types +@comment node-name, next, previous, up +@section NFS-Link Filesystem (@samp{nfsl}) +@cindex NFS-Link filesystem II +@cindex Referencing an existing part of the name space if target exists +@cindex Mounting a remote part of the name space if target is missing +@cindex Symlink if target exists, NFS otherwise +@cindex nfsl, filesystem type +@cindex symlink, nfsl filesystem type +@cindex Filesystem type; nfsl + +The @dfn{nfsl} (@samp{type:=nfsl}) filesystem type is a combination of two others: +@samp{link} and @samp{nfs}. If the local host name is equal to the +value of @code{$@{rhost@}}, or if the target pathname listed in +@code{$@{fs@}} exists, @samp{nfsl} will behave exactly as +@samp{type:=link}, and refer to the target as a symbolic link. If the +local host name is not equal to the value of @code{$@{rhost@}}, or if +the target of the link does not exist, @i{Amd} will treat it as +@samp{type:=nfs}, and will mount a remote pathname for it. + +The @samp{nfsl} filesystem type is particularly useful as a shorthand +for the more cumbersome and yet one of the most popular @i{Amd} +entries. For example, you can simplify all map entries that look like: + +@example +zing -fs:=/n/shekel/u/zing \ + host!=shekel;type:=nfs;rhost:=shekel;rfs:=$@{fs@} \ + host==shekel;type:=link +@end example + +or + +@example +zing -fs:=/n/shekel/u/zing \ + exists($@{fs@});type:=link \ + !exists($@{fs@});type:=nfs;rhost:=shekel;rfs:=$@{fs@} +@end example + +into a shorter form + +@example +zing type:=nfsl;fs:=/n/shekel/u/zing;rhost:=shekel;rfs:=$@{fs@} +@end example + +Not just does it make the maps smaller and simpler, but it avoids +possible mistakes that often happen when forgetting to set up the two +entries (one for @samp{type:=nfs} and the other for @samp{type:=link}) +necessary to perform transparent mounts of existing or remote mounts. + +@c ---------------------------------------------------------------- +@node Automount Filesystem, Direct Automount Filesystem, NFS-Link Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Automount Filesystem (@samp{auto}) +@cindex Automount filesystem +@cindex Map cache types +@cindex Setting map cache parameters +@cindex How to set map cache parameters +@cindex How to start an indirect automount point +@cindex auto, filesystem type +@cindex Filesystem type; auto +@cindex SIGHUP signal +@cindex Map cache synchronizing +@cindex Synchronizing the map cache +@cindex Map cache options +@cindex Regular expressions in maps + +The @dfn{auto} (@samp{type:=auto}) filesystem type creates a new automount point below an +existing automount point. Top-level automount points appear as system +mount points. An automount mount point can also appear as a +sub-directory of an existing automount point. This allows some +additional structure to be added, for example to mimic the mount tree of +another machine. + +The following options may be specified: + +@table @code +@cindex cache, mount option +@cindex Mount option; cache +@item cache +specifies whether the data in this mount-map should be +cached. The default value is @samp{none}, in which case +no caching is done in order to conserve memory. +However, better performance and reliability can be obtained by caching +some or all of a mount-map. + +If the cache option specifies @samp{all}, +the entire map is enumerated when the mount point is created. + +If the cache option specifies @samp{inc}, caching is done incrementally +as and when data is required. +Some map types do not support cache mode @samp{all}, in which case @samp{inc} +is used whenever @samp{all} is requested. + +Caching can be entirely disabled by using cache mode @samp{none}. + +If the cache option specifies @samp{regexp} then the entire map will be +enumerated and each key will be treated as an egrep-style regular +expression. The order in which a cached map is searched does not +correspond to the ordering in the source map so the regular expressions +should be mutually exclusive to avoid confusion. + +Each mount map type has a default cache type, usually @samp{inc}, which +can be selected by specifying @samp{mapdefault}. + +The cache mode for a mount map can only be selected on the command line. +Starting @i{Amd} with the command: + +@example +amd /homes hesiod.homes -cache:=inc +@end example + +will cause @samp{/homes} to be automounted using the @dfn{Hesiod} name +server with local incremental caching of all successfully resolved names. + +All cached data is forgotten whenever @i{Amd} receives a @samp{SIGHUP} +signal and, if cache @samp{all} mode was selected, the cache will be +reloaded. This can be used to inform @i{Amd} that a map has been +updated. In addition, whenever a cache lookup fails and @i{Amd} needs +to examine a map, the map's modify time is examined. If the cache is +out of date with respect to the map then it is flushed as if a +@samp{SIGHUP} had been received. + +An additional option (@samp{sync}) may be specified to force @i{Amd} to +check the map's modify time whenever a cached entry is being used. For +example, an incremental, synchronized cache would be created by the +following command: + +@example +amd /homes hesiod.homes -cache:=inc,sync +@end example + +@item fs +specifies the name of the mount map to use for the new mount point. + +Arguably this should have been specified with the @code{$@{rfs@}} option but +we are now stuck with it due to historical accident. + +@c %If the string @samp{.} is used then the same map is used; +@c %in addition the lookup prefix is set to the name of the mount point followed +@c %by a slash @samp{/}. +@c %This is the same as specifying @samp{fs:=\$@{map@};pref:=\$@{key@}/}. +@c + +@item pref +alters the name that is looked up in the mount map. If +@code{$@{pref@}}, the @dfn{prefix}, is non-null then it is prepended to +the name requested by the kernel @dfn{before} the map is searched. +@end table + +The server @samp{dylan.doc.ic.ac.uk} has two user disks: +@samp{/dev/dsk/2s0} and @samp{/dev/dsk/5s0}. These are accessed as +@samp{/home/dylan/dk2} and @samp{/home/dylan/dk5} respectively. Since +@samp{/home} is already an automount point, this naming is achieved with +the following map entries:@refill + +@example +dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/ +dylan/dk2 type:=ufs;dev:=/dev/dsk/2s0 +dylan/dk5 type:=ufs;dev:=/dev/dsk/5s0 +@end example + +@c ---------------------------------------------------------------- +@node Direct Automount Filesystem, Union Filesystem, Automount Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Direct Automount Filesystem (@samp{direct}) +@cindex Direct automount filesystem +@cindex How to start a direct automount point +@cindex direct, filesystem type +@cindex Filesystem type; direct + +The @dfn{direct} (@samp{type:=direct}) filesystem is almost identical to the automount +filesystem. Instead of appearing to be a directory of mount points, it +appears as a symbolic link to a mounted filesystem. The mount is done +at the time the link is accessed. @xref{Automount Filesystem} for a +list of required options. + +Direct automount points are created by specifying the @samp{direct} +filesystem type on the command line: + +@example +amd ... /usr/man auto.direct -type:=direct +@end example + +where @samp{auto.direct} would contain an entry such as: + +@example +usr/man -type:=nfs;rfs:=/usr/man \ + rhost:=man-server1 rhost:=man-server2 +@end example + +In this example, @samp{man-server1} and @samp{man-server2} are file +servers which export copies of the manual pages. Note that the key +which is looked up is the name of the automount point without the +leading @samp{/}. + +@c ---------------------------------------------------------------- +@node Union Filesystem, Error Filesystem, Direct Automount Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Union Filesystem (@samp{union}) +@cindex Union filesystem +@cindex union, filesystem type +@cindex Filesystem type; union + +The @dfn{union} (@samp{type:=union}) filesystem type allows the contents of several +directories to be merged and made visible in a single directory. This +can be used to overcome one of the major limitations of the Unix mount +mechanism which only allows complete directories to be mounted. + +For example, supposing @file{/tmp} and @file{/var/tmp} were to be merged +into a new directory called @file{/mtmp}, with files in @file{/var/tmp} +taking precedence. The following command could be used to achieve this +effect: + +@example +amd ... /mtmp union:/tmp:/var/tmp -type:=union +@end example + +Currently, the unioned directories must @emph{not} be automounted. That +would cause a deadlock. This seriously limits the current usefulness of +this filesystem type and the problem will be addressed in a future +release of @i{Amd}. + +Files created in the union directory are actually created in the last +named directory. This is done by creating a wildcard entry which points +to the correct directory. The wildcard entry is visible if the union +directory is listed, so allowing you to see which directory has +priority. + +The files visible in the union directory are computed at the time +@i{Amd} is started, and are not kept up-to-date with respect to the +underlying directories. Similarly, if a link is removed, for example +with the @samp{rm} command, it will be lost forever. + +@c ---------------------------------------------------------------- +@node Error Filesystem, Top-level Filesystem, Union Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Error Filesystem (@samp{error}) +@cindex Error filesystem +@cindex error, filesystem type +@cindex Filesystem type; error + +The @dfn{error} (@samp{type:=error}) filesystem type is used internally as a catch-all in the +case where none of the other filesystems was selected, or some other +error occurred. Lookups and mounts always fail with ``No such file or +directory''. All other operations trivially succeed. + +The error filesystem is not directly accessible. + +@c ---------------------------------------------------------------- +@node Top-level Filesystem, Autofs Filesystem, Error Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Top-level Filesystem (@samp{toplvl}) +@cindex Top level filesystem +@cindex toplvl, filesystem type +@cindex Filesystem type; toplvl + +The @dfn{toplvl} (@samp{type:=toplvl}) filesystems is derived from the @samp{auto} filesystem +and is used to mount the top-level automount nodes. Requests of this +type are automatically generated from the command line arguments and can +also be passed in by using the @code{-M} option of the @dfn{Amq} command. +That option is insecure, and is unavailable unless am-utils was +configured with @samp{--with-amq-mount}. + +@c ---------------------------------------------------------------- +@node Root Filesystem, Inheritance Filesystem, Autofs Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Root Filesystem (@samp{root}) +@cindex Root filesystem +@cindex root, filesystem type +@cindex Filesystem type; root + +The @dfn{root} (@samp{type:=root}) filesystem type acts as an internal +placeholder onto which @i{Amd} can pin @samp{toplvl} mounts. Only one +node of this type need ever exist and one is created automatically +during startup. The effect of having more than one root node is +undefined. + +The root filesystem is not directly accessible. + +@c ---------------------------------------------------------------- +@node Autofs Filesystem, Root Filesystem, Top-level Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Autofs Filesystem (@samp{autofs}) +@cindex Autofs filesystem +@cindex autofs, filesystem type +@cindex Filesystem type; autofs + +The @dfn{autofs} (@samp{type:=autofs}) filesystem uses Sun's kernel-based automounter +supporting filesystem for @i{Amd}'s mount points. Hence it is another +type of top level filesystem. + +The autofs filesystem is not directly accessible from @i{Amd} maps, but +only from the @file{amd.conf} file (@pxref{mount_type Parameter}). + +Note that Autofs support is still very early. See the distribution file +@file{README.autofs} for detail of what works and what does not. + +@c ---------------------------------------------------------------- +@node Inheritance Filesystem, , Root Filesystem, Filesystem Types +@comment node-name, next, previous, up +@section Inheritance Filesystem (@samp{inherit}) +@cindex Inheritance filesystem +@cindex Nodes generated on a restart +@cindex inherit, filesystem type +@cindex Filesystem type; inherit + +The @dfn{inheritance} (@samp{type:=inherit}) filesystem is not directly +accessible. Instead, internal mount nodes of this type are +automatically generated when @i{Amd} is started with the @code{-r} option. +At this time the system mount table is scanned to locate any filesystems +which are already mounted. If any reference to these filesystems is +made through @i{Amd} then instead of attempting to mount it, @i{Amd} +simulates the mount and @dfn{inherits} the filesystem. This allows a +new version of @i{Amd} to be installed on a live system simply by +killing the old daemon with @samp{SIGTERM} and starting the new one.@refill + +This filesystem type is not generally visible externally, but it is +possible that the output from @samp{amq -m} may list @samp{inherit} as +the filesystem type. This happens when an inherit operation cannot +be completed for some reason, usually because a fileserver is down. + +@c ################################################################ +@node Amd Configuration File, Run-time Administration, Filesystem Types, Top +@comment node-name, next, previous, up +@chapter Amd Configuration File +@cindex Amd Configuration File +@cindex amd.conf + +The @samp{amd.conf} file is the configuration file for @i{Amd}, as part +of the am-utils suite. This file contains runtime configuration +information for the @i{Amd} automounter program. + +@menu +* File Format:: +* The Global Section:: +* Regular Map Sections:: +* Common Parameters:: +* Global Parameters:: +* Regular Map Parameters:: +* amd.conf Examples:: +@end menu + +@c ================================================================ +@node File Format, The Global Section, Amd Configuration File, Amd Configuration File +@comment node-name, next, previous, up +@section File Format +@cindex amd.conf file format + +The @samp{amd.conf} file consists of sections and parameters. A section +begins with the name of the section in square brackets @samp{[]} and +continues until the next section begins or the end of the file is reached. +Sections contain parameters of the form @samp{name = value}. + +The file is line-based --- that is, each newline-terminated line +represents either a comment, a section name or a parameter. No +line-continuation syntax is available. + +Section names, parameter names and their values are case sensitive. + +Only the first equals sign in a parameter is significant. Whitespace +before or after the first equals sign is discarded. Leading, trailing +and internal whitespace in section and parameter names is irrelevant. +Leading and trailing whitespace in a parameter value is discarded. +Internal whitespace within a parameter value is not allowed, unless the +whole parameter value is quoted with double quotes as in @samp{name = +"some value"}. + +Any line beginning with a pound sign @samp{#} is ignored, as are lines +containing only whitespace. + +The values following the equals sign in parameters are all either a +string (no quotes needed if string does not include spaces) or a +boolean, which may be given as @samp{yes}/@samp{no}. Case is significant in all +values. Some items such as cache timeouts are numeric. + +@c ================================================================ +@node The Global Section, Regular Map Sections, File Format, Amd Configuration File +@comment node-name, next, previous, up +@section The Global Section +@cindex amd.conf global section + +The global section must be specified as @samp{[global]}. Parameters in +this section either apply to @i{Amd} as a whole, or to all other regular map +sections which follow. There should be only one global section defined +in one configuration file. + +It is highly recommended that this section be specified first in the +configuration file. If it is not, then regular map sections which +precede it will not use global values defined later. + +@c ================================================================ +@node Regular Map Sections, Common Parameters, The Global Section, Amd Configuration File +@comment node-name, next, previous, up +@section Regular Map Sections +@cindex amd.conf regular map sections + +Parameters in regular (non-global) sections apply to a single map entry. +For example, if the map section @samp{[/homes]} is defined, then all +parameters following it will be applied to the @file{/homes} +@i{Amd}-managed mount point. + +@c ================================================================ +@node Common Parameters, Global Parameters, Regular Map Sections, Amd Configuration File +@comment node-name, next, previous, up +@section Common Parameters +@cindex amd.conf common parameters + +These parameters can be specified either in the global or a map-specific +section. Entries specified in a map-specific section override the default +value or one defined in the global section. If such a common parameter is +specified only in the global section, it is applicable to all regular map +sections that follow. + +@menu +* browsable_dirs Parameter:: +* map_options Parameter:: +* map_type Parameter:: +* mount_type Parameter:: +* search_path Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node browsable_dirs Parameter, map_options Parameter, Common Parameters, Common Parameters +@comment node-name, next, previous, up +@subsection @t{browsable_dirs} Parameter +@cindex browsable_dirs Parameter + +(type=string, default=@samp{no}). If @samp{yes}, then @i{Amd}'s top-level +mount points will be browsable to @b{readdir}(3) calls. This means you +could run for example @b{ls}(1) and see what keys are available to mount +in that directory. Not all entries are made visible to @b{readdir}(3): +the @samp{/defaults} entry, wildcard entries, and those with a @file{/} +in them are not included. If you specify @samp{full} to this option, +all but the @samp{/defaults} entry will be visible. Note that if you run +a command which will attempt to @b{stat}(2) the entries, such as often +done by @samp{ls -l} or @samp{ls -F}, @i{Amd} will attempt to mount +@i{every} entry in that map. This is often called a ``mount storm''. + +@c ---------------------------------------------------------------- +@node map_options Parameter, map_type Parameter, browsable_dirs Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{map_options} Parameter +@cindex map_options Parameter + +(type=string, default no options). This option is the same as +specifying map options on the command line to @i{Amd}, such as +@samp{cache:=all}. + +@c ---------------------------------------------------------------- +@node map_type Parameter, mount_type Parameter, map_options Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{map_type} Parameter +@cindex map_type Parameter + +(type=string, default search all map types). If specified, @i{Amd} will +initialize the map only for the type given. This is useful to avoid the +default map search type used by @i{Amd} which takes longer and can have +undesired side-effects such as initializing NIS even if not used. +Possible values are + +@table @samp +@item file +plain files +@item hesiod +Hesiod name service from MIT +@item ldap +Lightweight Directory Access Protocol +@item ndbm +(New) dbm style hash files +@item nis +Network Information Services (version 2) +@item nisplus +Network Information Services Plus (version 3) +@item passwd +local password files +@item union +union maps +@end table + +@c ---------------------------------------------------------------- +@node mount_type Parameter, search_path Parameter, map_type Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{mount_type} Parameter +@cindex mount_type Parameter + +(type=string, default=@samp{nfs}). All @i{Amd} mount types default to NFS. +That is, @i{Amd} is an NFS server on the map mount points, for the local +host it is running on. If @samp{autofs} is specified, @i{Amd} will be +an autofs server for those mount points. + +@c ---------------------------------------------------------------- +@node search_path Parameter, , mount_type Parameter, Common Parameters +@comment node-name, next, previous, up +@subsection @t{search_path} Parameter +@cindex search_path Parameter + +(type=string, default no search path). This provides a +(colon-delimited) search path for file maps. Using a search path, +sites can allow for local map customizations and overrides, and can +distributed maps in several locations as needed. + +@c ================================================================ +@node Global Parameters, Regular Map Parameters, Common Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section Global Parameters +@cindex amd.conf global parameters + +The following parameters are applicable to the @samp{[global]} section only. + +@menu +* arch Parameter:: +* auto_dir Parameter:: +* cache_duration Parameter:: +* cluster Parameter:: +* debug_options Parameter:: +* dismount_interval Parameter:: +* fully_qualified_hosts Parameter:: +* hesiod_base Parameter:: +* karch Parameter:: +* ldap_base Parameter:: +* ldap_cache_maxmem Parameter:: +* ldap_cache_seconds Parameter:: +* ldap_hostports Parameter:: +* local_domain Parameter:: +* log_file Parameter:: +* log_options Parameter:: +* nfs_retransmit_counter Parameter:: +* nfs_retry_interval Parameter:: +* nis_domain Parameter:: +* normalize_hostnames Parameter:: +* os Parameter:: +* osver Parameter:: +* pid_file Parameter:: +* plock Parameter:: +* portmap_program Parameter:: +* print_pid Parameter:: +* print_version Parameter:: +* restart_mounts Parameter:: +* selectors_on_default Parameter:: +* show_statfs_entries Parameter:: +* unmount_on_exit Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node arch Parameter, auto_dir Parameter, Global Parameters, Global Parameters +@comment node-name, next, previous, up +@subsection @t{arch} Parameter +@cindex arch Parameter + +(type=string, default to compiled in value). Allows you to override the +value of the @i{arch} @i{Amd} variable. + +@c ---------------------------------------------------------------- +@node auto_dir Parameter, cache_duration Parameter, arch Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{auto_dir} Parameter +@cindex auto_dir Parameter + +(type=string, default=@samp{/a}). Same as the @code{-a} option to @i{Amd}. +This sets the private directory where @i{Amd} will create +sub-directories for its real mount points. + +@c ---------------------------------------------------------------- +@node cache_duration Parameter, cluster Parameter, auto_dir Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{cache_duration} Parameter +@cindex cache_duration Parameter + +(type=numeric, default=300). Same as the @code{-c} option to +@i{Amd}. Sets the duration in seconds that looked up map entries remain +in the cache. + +@c ---------------------------------------------------------------- +@node cluster Parameter, debug_options Parameter, cache_duration Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{cluster} Parameter +@cindex cluster Parameter + +(type=string, default no cluster). Same as the @code{-C} option to +@i{Amd}. Specifies the alternate HP-UX cluster to use. + +@c ---------------------------------------------------------------- +@node debug_options Parameter, dismount_interval Parameter, cluster Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{debug_options} Parameter +@cindex debug_options Parameter + +(type=string, default no debug options). Same as the @code{-D} +option to @i{Amd}. Specify any debugging options for @i{Amd}. Works +only if am-utils was configured for debugging using the +@code{--enable-debug} option. The @samp{mem} option alone can be turned +on via @code{--enable-debug=mem}. Otherwise debugging options are +ignored. Options are comma delimited, and can be preceded by the string +@samp{no} to negate their meaning. You can get the list of supported +debugging options by running @code{amd -v}. Possible values are: + +@table @samp +@item all +all options +@item amq +register for amq +@item daemon +enter daemon mode +@item fork +fork server +@item full +program trace +@item mem +trace memory allocations +@item mtab +use local @file{./mtab} file +@item str +debug string munging +@item test +full debug but no daemon +@item trace +protocol trace +@end table + +@c ---------------------------------------------------------------- +@node dismount_interval Parameter, fully_qualified_hosts Parameter, debug_options Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{dismount_interval} Parameter +@cindex dismount_interval Parameter + +(type=numeric, default=120). Same as the @code{-w} option to +@i{Amd}. Specify in seconds, the time between attempts to dismount file +systems that have exceeded their cached times. + +@c ---------------------------------------------------------------- +@node fully_qualified_hosts Parameter, hesiod_base Parameter, dismount_interval Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{fully_qualified_hosts} Parameter +@cindex fully_qualified_hosts Parameter + +(type=string, default=@samp{no}). If @samp{yes}, @i{Amd} will perform RPC +authentication using fully-qualified host names. This is necessary for +some systems, and especially when performing cross-domain mounting. For +this function to work, the @i{Amd} variable @samp{$@{hostd@}} is used, +requiring that @samp{$@{domain@}} not be null. + +@c ---------------------------------------------------------------- +@node hesiod_base Parameter, karch Parameter, fully_qualified_hosts Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{hesiod_base} Parameter +@cindex hesiod_base Parameter + +(type=string, default=@samp{automount}). Specify the base name for +hesiod maps. + +@c ---------------------------------------------------------------- +@node karch Parameter, ldap_base Parameter, hesiod_base Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{karch} Parameter +@cindex karch Parameter + +(type=string, default to karch of the system). Same as the @code{-k} +option to @i{Amd}. Allows you to override the kernel-architecture of +your system. Useful for example on Sun (Sparc) machines, where you can +build one @i{Amd} binary, and run it on multiple machines, yet you want +each one to get the correct @i{karch} variable set (for example, sun4c, +sun4m, sun4u, etc.) Note that if not specified, @i{Amd} will use +@b{uname}(2) to figure out the kernel architecture of the machine. + +@c ---------------------------------------------------------------- +@node ldap_base Parameter, ldap_cache_maxmem Parameter, karch Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_base} Parameter +@cindex ldap_base Parameter + +(type=string, default not set). Specify the base name for +LDAP. + +@c ---------------------------------------------------------------- +@node ldap_cache_maxmem Parameter, ldap_cache_seconds Parameter, ldap_base Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_cache_maxmem} Parameter +@cindex ldap_cache_maxmem Parameter + +(type=numeric, default=131072). Specify the maximum memory @i{Amd} +should use to cache LDAP entries. + +@c ---------------------------------------------------------------- +@node ldap_cache_seconds Parameter, ldap_hostports Parameter, ldap_cache_maxmem Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_cache_seconds} Parameter +@cindex ldap_cache_seconds Parameter + +(type=numeric, default=0). Specify the number of seconds to keep +entries in the cache. + +@c ---------------------------------------------------------------- +@node ldap_hostports Parameter, local_domain Parameter, ldap_cache_seconds Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{ldap_hostports} Parameter +@cindex ldap_hostports Parameter + +(type=string, default not set). Specify +LDAP-specific values such as country and organization. + +@c ---------------------------------------------------------------- +@node local_domain Parameter, log_file Parameter, ldap_hostports Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{local_domain} Parameter +@cindex local_domain Parameter + +(type=string, default no sub-domain). Same as the @code{-d} option +to @i{Amd}. Specify the local domain name. If this option is not given +the domain name is determined from the hostname, by removing the first +component of the fully-qualified host name. + +@c ---------------------------------------------------------------- +@node log_file Parameter, log_options Parameter, local_domain Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{log_file} Parameter +@cindex log_file Parameter + +(type=string, default=@samp{stderr}). Same as the @code{-l} option to +@i{Amd}. Specify a file name to log @i{Amd} events to. +If the string @samp{/dev/stderr} is specified, +@i{Amd} will send its events to the standard error file descriptor. + +If the string @samp{syslog} is given, @i{Amd} will record its events +with the system logger @b{syslogd}(8). If your system supports syslog +facilities, then the default facility used is @samp{LOG_DAEMON}. + +When using syslog, if you wish to change the facility, append its name +to the option name, delimited by a single colon. For example, if it is +the string @samp{syslog:local7} then @i{Amd} will log messages via +@b{syslog}(3) using the @samp{LOG_LOCAL7} facility. If the facility +name specified is not recognized, @i{Amd} will default to @samp{LOG_DAEMON}. +Note: while you can use any syslog facility available on your system, it +is generally a bad idea to use those reserved for other services such as +@samp{kern}, @samp{lpr}, @samp{cron}, etc. + +@c ---------------------------------------------------------------- +@node log_options Parameter, nfs_retransmit_counter Parameter, log_file Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{log_options} Parameter +@cindex log_options Parameter + +(type=string, default no logging options). Same as the @code{-x} +option to @i{Amd}. Specify any logging options for @i{Amd}. Options +are comma delimited, and can be preceded by the string @samp{no} to +negate their meaning. The @samp{debug} logging option is only available +if am-utils was configured with @code{--enable-debug}. You can get the +list of supported debugging options by running @code{amd -v}. Possible +values are: + +@table @samp +@item all +all messages +@item debug +debug messages +@item error +non-fatal system errors +@item fatal +fatal errors +@item info +information +@item map +map errors +@item stats +additional statistical information +@item user +non-fatal user errors +@item warn +warnings +@item warning +warnings +@end table + +@c ---------------------------------------------------------------- +@node nfs_retransmit_counter Parameter, nfs_retry_interval Parameter, log_options Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nfs_retransmit_counter} Parameter +@cindex nfs_retransmit_counter Parameter + +(type=numeric, default=110). Same as the @i{counter} part of the +@code{-t} @i{interval.counter} option to @i{Amd}. Specifies the +retransmit counter's value in @emph{tenths} of seconds. + +@c ---------------------------------------------------------------- +@node nfs_retry_interval Parameter, nis_domain Parameter, nfs_retransmit_counter Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nfs_retry_interval} Parameter +@cindex nfs_retry_interval Parameter + +(type=numeric, default=8). Same as the @i{interval} part of the +@code{-t} @i{interval.counter} option to @i{Amd}. Specifies the +interval in @emph{tenths} of seconds, between NFS/RPC/UDP retries. + +@c ---------------------------------------------------------------- +@node nis_domain Parameter, normalize_hostnames Parameter, nfs_retry_interval Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{nis_domain} Parameter +@cindex nis_domain Parameter + +(type=string, default to local NIS domain name). Same as the +@code{-y} option to @i{Amd}. Specify an alternative NIS domain from +which to fetch the NIS maps. The default is the system domain name. +This option is ignored if NIS support is not available. + +@c ---------------------------------------------------------------- +@node normalize_hostnames Parameter, os Parameter, nis_domain Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{normalize_hostnames} Parameter +@cindex normalize_hostnames Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-n} option to @i{Amd}. +If @samp{yes}, then the name referred to by @code{$@{rhost@}} is normalized +relative to the host database before being used. The effect is to +translate aliases into ``official'' names. + +@c ---------------------------------------------------------------- +@node os Parameter, osver Parameter, normalize_hostnames Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{os} Parameter +@cindex os Parameter + +(type=string, default to compiled in value). Same as the @code{-O} +option to @i{Amd}. Allows you to override the compiled-in name of the +operating system. Useful when the built-in name is not desired for +backward compatibility reasons. For example, if the built-in name is +@samp{sunos5}, you can override it to @samp{sos5}, and use older maps +which were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node osver Parameter, pid_file Parameter, os Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{osver} Parameter +@cindex osver Parameter + +(type=string, default to compiled in value). Same as the @code{-o} +option to @i{Amd}. Allows you to override the compiled-in version +number of the operating system. Useful when the built-in version is not +desired for backward compatibility reasons. For example, if the build +in version is @samp{2.5.1}, you can override it to @samp{5.5.1}, and use +older maps that were written with the latter in mind. + +@c ---------------------------------------------------------------- +@node pid_file Parameter, plock Parameter, osver Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{pid_file} Parameter +@cindex pid_file Parameter + +(type=string, default=@samp{/dev/stdout}). Specify a file to store the process +ID of the running daemon into. If not specified, @i{Amd} will print its +process id onto the standard output. Useful for killing @i{Amd} after +it had run. Note that the PID of a running @i{Amd} can also be +retrieved via @i{Amq} (@pxref{Amq -p option}). + +This file is used only if the @samp{print_pid} option is on +(@pxref{print_pid Parameter}). + +@c ---------------------------------------------------------------- +@node plock Parameter, portmap_program Parameter, pid_file Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{plock} Parameter +@cindex plock Parameter + +(type=boolean, default=@samp{yes}). Same as the @code{-S} option to @i{Amd}. +If @samp{yes}, lock the running executable pages of @i{Amd} into memory. +To improve @i{Amd}'s performance, systems that support the @b{plock}(3) +call can lock the @i{Amd} process into memory. This way there is less +chance the operating system will schedule, page out, and swap the +@i{Amd} process as needed. This improves @i{Amd}'s performance, at the +cost of reserving the memory used by the @i{Amd} process (making it +unavailable for other processes). + +@c ---------------------------------------------------------------- +@node portmap_program Parameter, print_pid Parameter, plock Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{portmap_program} Parameter +@cindex portmap_program Parameter + +(type=numeric, default=300019). Specify an alternate Port-mapper RPC +program number, other than the official number. This is useful when +running multiple @i{Amd} processes. For example, you can run another +@i{Amd} in ``test'' mode, without affecting the primary @i{Amd} process +in any way. For safety reasons, the alternate program numbers that can +be specified must be in the range 300019-300029, inclusive. @i{Amq} has +an option @code{-P} which can be used to specify an alternate program +number of an @i{Amd} to contact. In this way, amq can fully control any +number of @i{Amd} processes running on the same host. + +@c ---------------------------------------------------------------- +@node print_pid Parameter, print_version Parameter, portmap_program Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{print_pid} Parameter +@cindex print_pid Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-p} option to @i{Amd}. +If @samp{yes}, @i{Amd} will print its process ID upon starting. + +@c ---------------------------------------------------------------- +@node print_version Parameter, restart_mounts Parameter, print_pid Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{print_version} Parameter +@cindex print_version Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-v} option to @i{Amd}, +but the version prints and @i{Amd} continues to run. If @samp{yes}, @i{Amd} +will print its version information string, which includes some +configuration and compilation values. + +@c ---------------------------------------------------------------- +@node restart_mounts Parameter, selectors_on_default Parameter, print_version Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{restart_mounts} Parameter +@cindex restart_mounts Parameter + +(type=boolean, default=@samp{no}). Same as the @code{-r} option to @i{Amd}. +If @samp{yes} @i{Amd} will scan the mount table to determine which file +systems are currently mounted. Whenever one of these would have been +auto-mounted, @i{Amd} inherits it. + +@c ---------------------------------------------------------------- +@node selectors_on_default Parameter, show_statfs_entries Parameter, restart_mounts Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{selectors_on_default} Parameter +@cindex selectors_on_default Parameter + +(type=boolean, default=@samp{no}). If @samp{yes}, then the @samp{/defaults} entry of +maps will be looked for and any selectors processed before setting defaults +for all other keys in that map. Useful when you want to set different +options for a complete map based on some parameters. For example, you +may want to better the NFS performance over slow slip-based networks as +follows: + +@example +/defaults \ + wire==slip-net;opts:=intr,rsize=1024,wsize=1024 \ + wire!=slip-net;opts:=intr,rsize=8192,wsize=8192 +@end example + +@c ---------------------------------------------------------------- +@node show_statfs_entries Parameter, unmount_on_exit Parameter , selectors_on_default Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{show_statfs_entries} Parameter +@cindex show_statfs_entries Parameter + +(type=boolean), default=@samp{no}). If @samp{yes}, then all maps which are +browsable will also show the number of entries (keys) they have when +@b{df}(1) runs. (This is accomplished by returning non-zero values to +the @b{statfs}(2) system call). + +@c ---------------------------------------------------------------- +@node unmount_on_exit Parameter, , show_statfs_entries Parameter, Global Parameters +@comment node-name, next, previous, up +@subsection @t{unmount_on_exit} Parameter +@cindex unmount_on_exit Parameter + +(type=boolean), default=@samp{no}). If @samp{yes}, then @i{Amd} will attempt +to unmount all file systems which it knows about. Normally it leaves +all (esp. NFS) mounted file systems intact. Note that @i{Amd} does not +know about file systems mounted before it starts up, unless the +@samp{restart_mounts} option is used (@pxref{restart_mounts Parameter}). + +@c ================================================================ +@node Regular Map Parameters, amd.conf Examples, Global Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section Regular Map Parameters +@cindex amd.conf regular map parameters + +The following parameters are applicable only to regular map sections. + +@menu +* map_name Parameter:: +* tag Parameter:: +@end menu + +@c ---------------------------------------------------------------- +@node map_name Parameter, tag Parameter, Regular Map Parameters, Regular Map Parameters +@comment node-name, next, previous, up +@subsection map_name Parameter +@cindex map_name Parameter + +(type=string, must be specified). Name of the map where the keys are +located. + +@c ---------------------------------------------------------------- +@node tag Parameter, , map_name Parameter, Regular Map Parameters +@comment node-name, next, previous, up +@subsection tag Parameter +@cindex tag Parameter + +(type=string, default no tag). Each map entry in the configuration file +can be tagged. If no tag is specified, that map section will always be +processed by @i{Amd}. If it is specified, then @i{Amd} will process the map +if the @code{-T} option was given to @i{Amd}, and the value given to that +command-line option matches that in the map section. + +@c ================================================================ +@node amd.conf Examples, , Regular Map Parameters, Amd Configuration File +@comment node-name, next, previous, up +@section amd.conf Examples +@cindex amd.conf examples + +The following is the actual @code{amd.conf} file I use at the +Computer Science Department of Columbia University. + +@example +# GLOBAL OPTIONS SECTION +[ global ] +normalize_hostnames = no +print_pid = no +#pid_file = /var/run/amd.pid +restart_mounts = yes +#unmount_on_exit = yes +auto_dir = /n +log_file = /var/log/amd +log_options = all +#debug_options = all +plock = no +selectors_on_default = yes +# config.guess picks up "sunos5" and I don't want to edit my maps yet +os = sos5 +# if you print_version after setting up "os", it will show it. +print_version = no +map_type = file +search_path = /etc/amdmaps:/usr/lib/amd:/usr/local/AMD/lib +browsable_dirs = yes +fully_qualified_hosts = no + +# DEFINE AN AMD MOUNT POINT +[ /u ] +map_name = amd.u + +[ /proj ] +map_name = amd.proj + +[ /src ] +map_name = amd.src + +[ /misc ] +map_name = amd.misc + +[ /import ] +map_name = amd.import + +[ /tftpboot/.amd ] +tag = tftpboot +map_name = amd.tftpboot +@end example + +@c ################################################################ +@node Run-time Administration, FSinfo, Amd Configuration File, Top +@comment node-name, next, previous, up +@chapter Run-time Administration +@cindex Run-time administration +@cindex Amq command + +@menu +* Starting Amd:: +* Stopping Amd:: +* Restarting Amd:: +* Controlling Amd:: +@end menu + +@node Starting Amd, Stopping Amd, Run-time Administration, Run-time Administration +@comment node-name, next, previous, up +@section Starting @i{Amd} +@cindex Starting Amd +@cindex Additions to /etc/rc.local +@cindex /etc/rc.local additions +@cindex ctl-amd + +@i{Amd} is best started from @samp{/etc/rc.local} on BSD systems, or +from the appropriate start-level script in @samp{/etc/init.d} on System V +systems. + +@example +if [ -f /usr/local/sbin/ctl-amd ]; then + /usr/local/sbin/ctl-amd start; (echo -n ' amd') > /dev/console +fi +@end example + +@noindent +The shell script, @samp{ctl-amd} is used to start, stop, or restart +@i{Amd}. It is a relatively generic script. All options you want to +set should not be made in this script, but rather updated in the +@file{amd.conf} file. @xref{Amd Configuration File}. + +If you do not wish to use an @i{Amd} configuration file, you may start +@i{Amd} manually. For example, getting the map entries via NIS: + +@example +amd -r -l /var/log/amd `ypcat -k auto.master` +@end example + +@node Stopping Amd, Restarting Amd, Starting Amd, Run-time Administration +@comment node-name, next, previous, up +@section Stopping @i{Amd} +@cindex Stopping Amd +@cindex SIGTERM signal +@cindex SIGINT signal + +@i{Amd} stops in response to two signals. + +@table @samp +@item SIGTERM +causes the top-level automount points to be unmounted and then @i{Amd} +to exit. Any automounted filesystems are left mounted. They can be +recovered by restarting @i{Amd} with the @code{-r} command line option.@refill + +@item SIGINT +causes @i{Amd} to attempt to unmount any filesystems which it has +automounted, in addition to the actions of @samp{SIGTERM}. This signal +is primarily used for debugging.@refill +@end table + +Actions taken for other signals are undefined. + +The easiest and safest way to stop @i{Amd}, without having to find its +process ID by hand, is to use the @file{ctl-amd} script, as with: + +@example +ctl-amd stop +@end example + +@node Restarting Amd, Controlling Amd, Stopping Amd, Run-time Administration +@comment node-name, next, previous, up +@section Restarting @i{Amd} +@cindex Restarting Amd +@cindex Killing and starting Amd + +Before @i{Amd} can be started, it is vital to ensure that no other +@i{Amd} processes are managing any of the mount points, and that the +previous process(es) have terminated cleanly. When a terminating signal +is set to @i{Amd}, the automounter does @emph{not} terminate right then. +Rather, it starts by unmounting all of its managed mount mounts in the +background, and then terminates. It usually takes a few seconds for +this process to happen, but it can take an arbitrarily longer time. If +two or more @i{Amd} processes attempt to manage the same mount point, it +usually will result in a system lockup. + +The easiest and safest way to restart @i{Amd}, without having to find +its process ID by hand, sending it the @samp{SIGTERM} signal, waiting for @i{Amd} +to die cleanly, and verifying so, is to use the @file{ctl-amd} script, +as with: + +@example +ctl-amd restart +@end example + +The script will locate the process ID of @i{Amd}, kill it, and wait for +it to die cleanly before starting a new instance of the automounter. +@file{ctl-amd} will wait for a total of 30 seconds for @i{Amd} to die, +and will check once every 5 seconds if it had. + +@node Controlling Amd, , Restarting Amd, Run-time Administration +@comment node-name, next, previous, up +@section Controlling @i{Amd} +@cindex Controlling Amd +@cindex Discovering what is going on at run-time +@cindex Listing currently mounted filesystems + +It is sometimes desirable or necessary to exercise external control +over some of @i{Amd}'s internal state. To support this requirement, +@i{Amd} implements an RPC interface which is used by the @dfn{Amq} program. +A variety of information is available. + +@i{Amq} generally applies an operation, specified by a single letter option, +to a list of mount points. The default operation is to obtain statistics +about each mount point. This is similar to the output shown above +but includes information about the number and type of accesses to each +mount point. + +@menu +* Amq default:: Default command behavior. +* Amq -f option:: Flushing the map cache. +* Amq -h option:: Controlling a non-local host. +* Amq -l option:: Controlling the log file. +* Amq -m option:: Obtaining mount statistics. +* Amq -M-option:: Mounting a volume. +* Amq -p option:: Getting Amd's process ID. +* Amq -P-option:: Contacting alternate Amd processes. +* Amq -s option:: Obtaining global statistics. +* Amq -T option:: Use TCP transport. +* Amq -U-option:: Use UDP transport. +* Amq -u option:: Forcing volumes to time out. +* Amq -v option:: Version information. +* Other Amq options:: Three other special options. +@end menu + +@c ---------------------------------------------------------------- +@node Amq default, Amq -f option, Controlling Amd, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} default information + +With no arguments, @dfn{Amq} obtains a brief list of all existing +mounts created by @i{Amd}. This is different from the list displayed by +@b{df}(1) since the latter only includes system mount points. + +@noindent +The output from this option includes the following information: + +@itemize @bullet +@item +the automount point, +@item +the filesystem type, +@item +the mount map or mount information, +@item +the internal, or system mount point. +@end itemize + +@noindent +For example: + +@example +/ root "root" sky:(pid75) +/homes toplvl /usr/local/etc/amd.homes /homes +/home toplvl /usr/local/etc/amd.home /home +/homes/jsp nfs charm:/home/charm /a/charm/home/charm/jsp +/homes/phjk nfs toytown:/home/toytown /a/toytown/home/toytown/ai/phjk +@end example + +@noindent +If an argument is given then statistics for that volume name will +be output. For example: + +@example +What Uid Getattr Lookup RdDir RdLnk Statfs Mounted@@ +/homes 0 1196 512 22 0 30 90/09/14 12:32:55 +/homes/jsp 0 0 0 0 1180 0 90/10/13 12:56:58 +@end example + +@table @code +@item What +the volume name. + +@item Uid +ignored. + +@item Getattr +the count of NFS @dfn{getattr} requests on this node. This should only be +non-zero for directory nodes. + +@item Lookup +the count of NFS @dfn{lookup} requests on this node. This should only be +non-zero for directory nodes. + +@item RdDir +the count of NFS @dfn{readdir} requests on this node. This should only +be non-zero for directory nodes. + +@item RdLnk +the count of NFS @dfn{readlink} requests on this node. This should be +zero for directory nodes. + +@item Statfs +the count of NFS @dfn{statfs} requests on this node. This should only +be non-zero for top-level automount points. + +@item Mounted@@ +the date and time the volume name was first referenced. +@end table + +@c ---------------------------------------------------------------- +@node Amq -f option, Amq -h option, Amq default, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-f} option +@cindex Flushing the map cache +@cindex Map cache, flushing + +The @code{-f} option causes @i{Amd} to flush the internal mount map cache. +This is useful for example in Hesiod maps since @i{Amd} will not +automatically notice when they have been updated. The map cache can +also be synchronized with the map source by using the @samp{sync} option +(@pxref{Automount Filesystem}).@refill + +@c ---------------------------------------------------------------- +@node Amq -l option, Amq -m option, Amq -h option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-l} option +@cindex Resetting the Amd log file +@cindex Setting the Amd log file via Amq +@cindex Log file, resetting + +Tell @i{Amd} to use @i{log_file} as the log file name. For security +reasons, this @emph{must} be the same log file which @i{Amd} used when +started. This option is therefore only useful to refresh @i{Amd}'s open +file handle on the log file, so that it can be rotated and compressed +via daily cron jobs. + +@c ---------------------------------------------------------------- +@node Amq -h option, Amq -l option, Amq -f option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-h} option +@cindex Querying an alternate host + +By default the local host is used. In an HP-UX cluster the root server +is used since that is the only place in the cluster where @i{Amd} will +be running. To query @i{Amd} on another host the @code{-h} option should +be used. + +@c ---------------------------------------------------------------- +@node Amq -m option, Amq -M-option, Amq -l option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-m} option + +The @code{-m} option displays similar information about mounted +filesystems, rather than automount points. The output includes the +following information: + +@itemize @bullet +@item +the mount information, +@item +the mount point, +@item +the filesystem type, +@item +the number of references to this filesystem, +@item +the server hostname, +@item +the state of the file server, +@item +any error which has occurred. +@end itemize + +For example: + +@example +"root" truth:(pid602) root 1 localhost is up +hesiod.home /home toplvl 1 localhost is up +hesiod.vol /vol toplvl 1 localhost is up +hesiod.homes /homes toplvl 1 localhost is up +amy:/home/amy /a/amy/home/amy nfs 5 amy is up +swan:/home/swan /a/swan/home/swan nfs 0 swan is up (Permission denied) +ex:/home/ex /a/ex/home/ex nfs 0 ex is down +@end example + +When the reference count is zero the filesystem is not mounted but +the mount point and server information is still being maintained +by @i{Amd}. + +@c ---------------------------------------------------------------- +@node Amq -M-option, Amq -p option, Amq -m option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-M} option + +The @code{-M} option passes a new map entry to @i{Amd} and waits for it to +be evaluated, possibly causing a mount. For example, the following +command would cause @samp{/home/toytown} on host @samp{toytown} to be +mounted locally on @samp{/mnt/toytown}. + +@example +amq -M '/mnt/toytown type:=nfs;rfs:=/home/toytown;rhost:=toytown;fs:=$@{key@}' +@end example + +@i{Amd} applies some simple security checks before allowing this +operation. The check tests whether the incoming request is from a +privileged UDP port on the local machine. ``Permission denied'' is +returned if the check fails. + +This option is very insecure as it is vulnerable to attacks such as IP +Spoofing. In other words, it is relatively easy for an attacker who +really wants to, to make your @i{Amd} process mount any filesystem from +the Internet! Therefore, the @emph{complete} code which supports the +@code{-M} option in @i{Amd} and @i{Amq} is turned off by default. To turn +it on, you have to reconfigure am-utils with @code{configure +--enable-amq-mount}. Think twice before doing so, and use this option +only if you absolutely need to. + +A future release of @i{Amd} will include code to allow the @b{mount}(8) +command to mount automount points: + +@example +mount -t amd /vol hesiod.vol +@end example + +This will then allow @i{Amd} to be controlled from the standard system +filesystem mount list. + +@c ---------------------------------------------------------------- +@node Amq -p option, Amq -P-option, Amq -M-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-p} option +@cindex Process ID; Amd +@cindex Amd's process ID +@cindex Amd's PID +@cindex PID; Amd + +Return the process ID of the remote or locally running @i{Amd}. Useful +when you need to send a signal to the local @i{Amd} process, and would +rather not have to search through the process table. This option is +used in the @file{ctl-amd} script. + +@c ---------------------------------------------------------------- +@node Amq -P-option, Amq -s option, Amq -p option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-P} option +@cindex Multiple Amd processes +@cindex Running multiple Amd +@cindex Debugging a new Amd configuration +@cindex RPC Program numbers; Amd + +Contact an alternate running @i{Amd} that had registered itself on a +different RPC @var{program_number} and apply all other operations to +that instance of the automounter. This is useful when you run multiple +copies of @i{Amd}, and need to manage each one separately. If not +specified, @i{Amq} will use the default program number for @i{Amd}, 300019. +For security reasons, the only alternate program numbers @i{Amd} can use +range from 300019 to 300029, inclusive. + +For example, to kill an alternate running @i{Amd}: + +@example +kill `amq -p -P 300020` +@end example + +@c ---------------------------------------------------------------- +@node Amq -s option, Amq -T option, Amq -P-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-s} option +@cindex Global statistics +@cindex Statistics + +The @code{-s} option displays global statistics. If any other options are specified +or any filesystems named then this option is ignored. For example: + +@example +requests stale mount mount unmount +deferred fhandles ok failed failed +1054 1 487 290 7017 +@end example + +@table @samp +@item Deferred requests +are those for which an immediate reply could not be constructed. For +example, this would happen if a background mount was required. + +@item Stale filehandles +counts the number of times the kernel passes a stale filehandle to @i{Amd}. +Large numbers indicate problems. + +@item Mount ok +counts the number of automounts which were successful. + +@item Mount failed +counts the number of automounts which failed. + +@item Unmount failed +counts the number of times a filesystem could not be unmounted. Very +large numbers here indicate that the time between unmount attempts +should be increased. +@end table + +@c ---------------------------------------------------------------- +@node Amq -T option, Amq -U-option, Amq -s option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-T} option +@cindex Forcing Amq to use a TCP transport +@cindex TCP; using with Amq + +The @code{-T} option causes the @i{Amq} to contact @i{Amd} using the TCP +transport only (connection oriented). Normally, @i{Amq} will use TCP +first, and if that failed, will try UDP. + +@c ---------------------------------------------------------------- +@node Amq -U-option, Amq -u option, Amq -T option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-U} option +@cindex Forcing Amq to use a UDP transport +@cindex UDP; using with Amq + +The @code{-U} option causes the @i{Amq} to contact @i{Amd} using the UDP +transport only (connectionless). Normally, @i{Amq} will use TCP first, +and if that failed, will try UDP. + +@c ---------------------------------------------------------------- +@node Amq -u option, Amq -v option, Amq -U-option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-u} option +@cindex Forcing filesystem to time out +@cindex Unmounting a filesystem + +The @code{-u} option causes the time-to-live interval of the named mount +points to be expired, thus causing an unmount attempt. This is the only +safe way to unmount an automounted filesystem. It is not possible to +unmount a filesystem which has been mounted with the @samp{nounmount} +flag. + +@c The @code{-H} option informs @i{Amd} that the specified mount point has hung - +@c as if its keepalive timer had expired. + +@c ---------------------------------------------------------------- +@node Amq -v option, Other Amq options, Amq -u option, Controlling Amd +@comment node-name, next, previous, up +@subsection @i{Amq} @code{-v} option +@cindex Version information at run-time + +The @code{-v} option displays the version of @i{Amd} in a similar way to +@i{Amd}'s @code{-v} option. + +@c ---------------------------------------------------------------- +@node Other Amq options, , Amq -v option, Controlling Amd +@comment node-name, next, previous, up +@subsection Other @i{Amq} options +@cindex Logging options via Amq +@cindex Debugging options via Amq + +Two other operations are implemented. These modify the state of @i{Amd} +as a whole, rather than any particular filesystem. The @code{-x} and +@code{-D} options have exactly the same effect as @i{Amd}'s corresponding +command line options. + +When @i{Amd} receives a @code{-x} flag it limits the log options being +modified to those which were not enabled at startup. This prevents a +user turning @emph{off} any logging option which was specified at +startup, though any which have been turned on since then can still be +turned off. The @code{-D} option has a similar behavior. + +@c ################################################################ +@node FSinfo, Hlfsd, Run-time Administration, Top +@comment node-name, next, previous, up +@chapter FSinfo +@cindex FSinfo +@cindex Filesystem info package + +XXX: this chapter should be reviewed by someone knowledgeable with +fsinfo. + +@menu +* FSinfo Overview:: Introduction to FSinfo. +* Using FSinfo:: Basic concepts. +* FSinfo Grammar:: Language syntax, semantics and examples. +* FSinfo host definitions:: Defining a new host. +* FSinfo host attributes:: Definable host attributes. +* FSinfo filesystems:: Defining locally attached filesystems. +* FSinfo static mounts:: Defining additional static mounts. +* FSinfo automount definitions:: +* FSinfo Command Line Options:: +* FSinfo errors:: +@end menu + +@node FSinfo Overview, Using FSinfo, FSinfo, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} overview +@cindex FSinfo overview + +@i{FSinfo} is a filesystem management tool. It has been designed to +work with @i{Amd} to help system administrators keep track of the ever +increasing filesystem namespace under their control. + +The purpose of @i{FSinfo} is to generate all the important standard +filesystem data files from a single set of input data. Starting with a +single data source guarantees that all the generated files are +self-consistent. One of the possible output data formats is a set of +@i{Amd} maps which can be used amongst the set of hosts described in the +input data. + +@i{FSinfo} implements a declarative language. This language is +specifically designed for describing filesystem namespace and physical +layouts. The basic declaration defines a mounted filesystem including +its device name, mount point, and all the volumes and access +permissions. @i{FSinfo} reads this information and builds an internal +map of the entire network of hosts. Using this map, many different data +formats can be produced including @file{/etc/fstab}, +@file{/etc/exports}, @i{Amd} mount maps and +@file{/etc/bootparams}.@refill + +@node Using FSinfo, FSinfo Grammar, FSinfo Overview, FSinfo +@comment node-name, next, previous, up +@section Using @i{FSinfo} +@cindex Using FSinfo + +The basic strategy when using @i{FSinfo} is to gather all the +information about all disks on all machines into one set of +declarations. For each machine being managed, the following data is +required: + +@itemize @bullet +@item +Hostname +@item +List of all filesystems and, optionally, their mount points. +@item +Names of volumes stored on each filesystem. +@item +NFS export information for each volume. +@item +The list of static filesystem mounts. +@end itemize + +The following information can also be entered into the same +configuration files so that all data can be kept in one place. + +@itemize @bullet +@item +List of network interfaces +@item +IP address of each interface +@item +Hardware address of each interface +@item +Dumpset to which each filesystem belongs +@item +and more @dots{} +@end itemize + +To generate @i{Amd} mount maps, the automount tree must also be defined +(@pxref{FSinfo automount definitions}). This will have been designed at +the time the volume names were allocated. Some volume names will not be +automounted, so @i{FSinfo} needs an explicit list of which volumes +should be automounted.@refill + +Hostnames are required at several places in the @i{FSinfo} language. It +is important to stick to either fully qualified names or unqualified +names. Using a mixture of the two will inevitably result in confusion. + +Sometimes volumes need to be referenced which are not defined in the set +of hosts being managed with @i{FSinfo}. The required action is to add a +dummy set of definitions for the host and volume names required. Since +the files generated for those particular hosts will not be used on them, +the exact values used is not critical. + +@node FSinfo Grammar, FSinfo host definitions, Using FSinfo, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} grammar +@cindex FSinfo grammar +@cindex Grammar, FSinfo + +@i{FSinfo} has a relatively simple grammar. Distinct syntactic +constructs exist for each of the different types of data, though they +share a common flavor. Several conventions are used in the grammar +fragments below. + +The notation, @i{list(}@t{xxx}@i{)}, indicates a list of zero or more +@t{xxx}'s. The notation, @i{opt(}@t{xxx}@i{)}, indicates zero or one +@t{xxx}. Items in double quotes, @i{eg} @t{"host"}, represent input +tokens. Items in angle brackets, @i{eg} @var{<hostname>}, represent +strings in the input. Strings need not be in double quotes, except to +differentiate them from reserved words. Quoted strings may include the +usual set of C ``@t{\}'' escape sequences with one exception: a +backslash-newline-whitespace sequence is squashed into a single space +character. To defeat this feature, put a further backslash at the start +of the second line. + +At the outermost level of the grammar, the input consists of a +sequence of host and automount declarations. These declarations are +all parsed before they are analyzed. This means they can appear in +any order and cyclic host references are possible. + +@example +fsinfo : @i{list(}fsinfo_attr@i{)} ; + +fsinfo_attr : host | automount ; +@end example + +@menu +* FSinfo host definitions:: +* FSinfo automount definitions:: +@end menu + +@node FSinfo host definitions, FSinfo host attributes, FSinfo Grammar, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} host definitions +@cindex FSinfo host definitions +@cindex Defining a host, FSinfo + +A host declaration consists of three parts: a set of machine attribute +data, a list of filesystems physically attached to the machine, and a +list of additional statically mounted filesystems. + +@example +host : "host" host_data @i{list(}filesystem@i{@i{)}} @i{list(}mount@i{@i{)}} ; +@end example + +Each host must be declared in this way exactly once. Such things as the +hardware address, the architecture and operating system types and the +cluster name are all specified within the @dfn{host data}. + +All the disks the machine has should then be described in the @dfn{list +of filesystems}. When describing disks, you can specify what +@dfn{volname} the disk/partition should have and all such entries are +built up into a dictionary which can then be used for building the +automounter maps. + +The @dfn{list of mounts} specifies all the filesystems that should be +statically mounted on the machine. + +@menu +* FSinfo host attributes:: +* FSinfo filesystems:: +* FSinfo static mounts:: +@end menu + +@node FSinfo host attributes, FSinfo filesystems, FSinfo host definitions , FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} host attributes +@cindex FSinfo host attributes +@cindex Defining host attributes, FSinfo + +The host data, @dfn{host_data}, always includes the @dfn{hostname}. In +addition, several other host attributes can be given. + +@example +host_data : @var{<hostname>} + | "@{" @i{list(}host_attrs@i{)} "@}" @var{<hostname>} + ; + +host_attrs : host_attr "=" @var{<string>} + | netif + ; + +host_attr : "config" + | "arch" + | "os" + | "cluster" + ; +@end example + +The @dfn{hostname} is, typically, the fully qualified hostname of the +machine. + +Examples: + +@example +host dylan.doc.ic.ac.uk + +host @{ + os = hpux + arch = hp300 +@} dougal.doc.ic.ac.uk +@end example + +The options that can be given as host attributes are shown below. + +@menu +* netif Option: FSinfo host netif: +* config Option: FSinfo host config: +* arch Option: FSinfo host arch: +* os Option: FSinfo host os: +* cluster Option: FSinfo host cluster: +@end menu + +@node FSinfo host netif, FSinfo host config, , FSinfo host attributes +@comment node-name, next, previous, up +@subsection netif Option + +This defines the set of network interfaces configured on the machine. +The interface attributes collected by @i{FSinfo} are the IP address, +subnet mask and hardware address. Multiple interfaces may be defined +for hosts with several interfaces by an entry for each interface. The +values given are sanity checked, but are currently unused for anything +else. + +@example +netif : "netif" @var{<string>} "@{" @i{list(}netif_attrs@i{)} "@}" ; + +netif_attrs : netif_attr "=" @var{<string>} ; + +netif_attr : "inaddr" | "netmask" | "hwaddr" ; +@end example + +Examples: + +@example +netif ie0 @{ + inaddr = 129.31.81.37 + netmask = 0xfffffe00 + hwaddr = "08:00:20:01:a6:a5" +@} + +netif ec0 @{ @} +@end example + +@node FSinfo host config, FSinfo host arch, FSinfo host netif, FSinfo host attributes +@comment node-name, next, previous, up +@subsection config Option +@cindex FSinfo config host attribute +@cindex config, FSinfo host attribute + +This option allows you to specify configuration variables for the +startup scripts (@file{rc} scripts). A simple string should immediately +follow the keyword. + +Example: + +@example +config "NFS_SERVER=true" +config "ZEPHYR=true" +@end example + +This option is currently unsupported. + +@node FSinfo host arch, FSinfo host os, FSinfo host config, FSinfo host attributes +@comment node-name, next, previous, up +@subsection arch Option +@cindex FSinfo arch host attribute +@cindex arch, FSinfo host attribute + +This defines the architecture of the machine. For example: + +@example +arch = hp300 +@end example + +This is intended to be of use when building architecture specific +mountmaps, however, the option is currently unsupported. + +@node FSinfo host os, FSinfo host cluster, FSinfo host arch, FSinfo host attributes +@comment node-name, next, previous, up +@subsection os Option +@cindex FSinfo os host attribute +@cindex os, FSinfo host attribute + +This defines the operating system type of the host. For example: + +@example +os = hpux +@end example + +This information is used when creating the @file{fstab} files, for +example in choosing which format to use for the @file{fstab} entries +within the file. + +@node FSinfo host cluster, , FSinfo host os, FSinfo host attributes +@comment node-name, next, previous, up +@subsection cluster Option +@cindex FSinfo cluster host attribute +@cindex cluster, FSinfo host attribute + +This is used for specifying in which cluster the machine belongs. For +example: + +@example +cluster = "theory" +@end example + +The cluster is intended to be used when generating the automount maps, +although it is currently unsupported. + +@node FSinfo filesystems, FSinfo static mounts, FSinfo host attributes, FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} filesystems +@cindex FSinfo filesystems + +The list of physically attached filesystems follows the machine +attributes. These should define all the filesystems available from this +machine, whether exported or not. In addition to the device name, +filesystems have several attributes, such as filesystem type, mount +options, and @samp{fsck} pass number which are needed to generate +@file{fstab} entries. + +@example +filesystem : "fs" @var{<device>} "@{" @i{list(}fs_data@i{)} "@}" ; + +fs_data : fs_data_attr "=" @var{<string>} + | mount + ; + +fs_data_attr + : "fstype" | "opts" | "passno" + | "freq" | "dumpset" | "log" + ; +@end example + +Here, @var{<device>} is the device name of the disk (for example, +@file{/dev/dsk/2s0}). The device name is used for building the mount +maps and for the @file{fstab} file. The attributes that can be +specified are shown in the following section. + +The @i{FSinfo} configuration file for @code{dylan.doc.ic.ac.uk} is listed below. + +@example +host dylan.doc.ic.ac.uk + +fs /dev/dsk/0s0 @{ + fstype = swap +@} + +fs /dev/dsk/0s0 @{ + fstype = hfs + opts = rw,noquota,grpid + passno = 0; + freq = 1; + mount / @{ @} +@} + +fs /dev/dsk/1s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount /usr @{ + local @{ + exportfs "dougal eden dylan zebedee brian" + volname /nfs/hp300/local + @} + @} +@} + +fs /dev/dsk/2s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk2 + @} +@} + +fs /dev/dsk/3s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk3 + @} +@} + +fs /dev/dsk/5s0 @{ + fstype = hfs + opts = defaults + passno = 1; + freq = 1; + mount default @{ + exportfs "toytown_clients hangers_on" + volname /home/dylan/dk5 + @} +@} +@end example + +@menu +* fstype Option: FSinfo filesystems fstype: +* opts Option: FSinfo filesystems opts: +* passno Option: FSinfo filesystems passno: +* freq Option: FSinfo filesystems freq: +* mount Option: FSinfo filesystems mount: +* dumpset Option: FSinfo filesystems dumpset: +* log Option: FSinfo filesystems log: +@end menu + +@node FSinfo filesystems fstype, FSinfo filesystems opts, , FSinfo filesystems +@comment node-name, next, previous, up +@subsection fstype Option +@cindex FSinfo fstype filesystems option +@cindex fstype, FSinfo filesystems option +@cindex export, FSinfo special fstype + +This specifies the type of filesystem being declared and will be placed +into the @file{fstab} file as is. The value of this option will be +handed to @code{mount} as the filesystem type---it should have such +values as @code{4.2}, @code{nfs} or @code{swap}. The value is not +examined for correctness. + +There is one special case. If the filesystem type is specified as +@samp{export} then the filesystem information will not be added to the +host's @file{fstab} information, but it will still be visible on the +network. This is useful for defining hosts which contain referenced +volumes but which are not under full control of @i{FSinfo}. + +Example: + +@example +fstype = swap +@end example + +@node FSinfo filesystems opts, FSinfo filesystems passno, FSinfo filesystems fstype, FSinfo filesystems +@comment node-name, next, previous, up +@subsection opts Option +@cindex FSinfo opts filesystems option +@cindex opts, FSinfo filesystems option + +This defines any options that should be given to @b{mount}(8) in the +@file{fstab} file. For example: + +@example +opts = rw,nosuid,grpid +@end example + +@node FSinfo filesystems passno, FSinfo filesystems freq, FSinfo filesystems opts, FSinfo filesystems +@comment node-name, next, previous, up +@subsection passno Option +@cindex FSinfo passno filesystems option +@cindex passno, FSinfo filesystems option + +This defines the @b{fsck}(8) pass number in which to check the +filesystem. This value will be placed into the @file{fstab} file. + +Example: + +@example +passno = 1 +@end example + +@node FSinfo filesystems freq, FSinfo filesystems mount, FSinfo filesystems passno, FSinfo filesystems +@comment node-name, next, previous, up +@subsection freq Option +@cindex FSinfo freq filesystems option +@cindex freq, FSinfo filesystems option + +This defines the interval (in days) between dumps. The value is placed +as is into the @file{fstab} file. + +Example: + +@example +freq = 3 +@end example + +@node FSinfo filesystems mount, FSinfo filesystems dumpset, FSinfo filesystems freq, FSinfo filesystems +@comment node-name, next, previous, up +@subsection mount Option +@cindex FSinfo mount filesystems option +@cindex mount, FSinfo filesystems option +@cindex exportfs, FSinfo mount option +@cindex volname, FSinfo mount option +@cindex sel, FSinfo mount option + +This defines the mountpoint at which to place the filesystem. If the +mountpoint of the filesystem is specified as @code{default}, then the +filesystem will be mounted in the automounter's tree under its volume +name and the mount will automatically be inherited by the automounter. + +Following the mountpoint, namespace information for the filesystem may +be described. The options that can be given here are @code{exportfs}, +@code{volname} and @code{sel}. + +The format is: + +@example +mount : "mount" vol_tree ; + +vol_tree : @i{list(}vol_tree_attr@i{)} ; + +vol_tree_attr + : @var{<string>} "@{" @i{list(}vol_tree_info@i{)} vol_tree "@}" ; + +vol_tree_info + : "exportfs" @var{<export-data>} + | "volname" @var{<volname>} + | "sel" @var{<selector-list>} + ; +@end example + +Example: + +@example +mount default @{ + exportfs "dylan dougal florence zebedee" + volname /vol/andrew +@} +@end example + +In the above example, the filesystem currently being declared will have +an entry placed into the @file{exports} file allowing the filesystem to +be exported to the machines @code{dylan}, @code{dougal}, @code{florence} +and @code{zebedee}. The volume name by which the filesystem will be +referred to remotely, is @file{/vol/andrew}. By declaring the +mountpoint to be @code{default}, the filesystem will be mounted on the +local machine in the automounter tree, where @i{Amd} will automatically +inherit the mount as @file{/vol/andrew}.@refill + +@table @samp +@item exportfs +a string defining which machines the filesystem may be exported to. +This is copied, as is, into the @file{exports} file---no sanity checking +is performed on this string.@refill + +@item volname +a string which declares the remote name by which to reference the +filesystem. The string is entered into a dictionary and allows you to +refer to this filesystem in other places by this volume name.@refill + +@item sel +a string which is placed into the automounter maps as a selector for the +filesystem.@refill + +@end table + +@node FSinfo filesystems dumpset, FSinfo filesystems log, FSinfo filesystems mount, FSinfo filesystems +@comment node-name, next, previous, up +@subsection dumpset Option +@cindex FSinfo dumpset filesystems option +@cindex dumpset, FSinfo filesystems option + +This provides support for Imperial College's local file backup tools and +is not documented further here. + +@node FSinfo filesystems log, , FSinfo filesystems dumpset, FSinfo filesystems +@comment node-name, next, previous, up +@subsection log Option +@cindex FSinfo log filesystems option +@cindex log, FSinfo filesystems option + +Specifies the log device for the current filesystem. This is ignored if +not required by the particular filesystem type. + +@node FSinfo static mounts, FSinfo automount definitions , FSinfo filesystems, FSinfo host definitions +@comment node-name, next, previous, up +@section @i{FSinfo} static mounts +@cindex FSinfo static mounts +@cindex Statically mounts filesystems, FSinfo + +Each host may also have a number of statically mounted filesystems. For +example, the host may be a diskless workstation in which case it will +have no @code{fs} declarations. In this case the @code{mount} +declaration is used to determine from where its filesystems will be +mounted. In addition to being added to the @file{fstab} file, this +information can also be used to generate a suitable @file{bootparams} +file.@refill + +@example +mount : "mount" @var{<volname>} @i{list(}localinfo@i{)} ; + +localinfo : localinfo_attr @var{<string>} ; + +localinfo_attr + : "as" + | "from" + | "fstype" + | "opts" + ; +@end example + +The filesystem specified to be mounted will be searched for in the +dictionary of volume names built when scanning the list of hosts' +definitions. + +The attributes have the following semantics: +@table @samp +@item from @var{machine} +mount the filesystem from the machine with the hostname of +@dfn{machine}.@refill + +@item as @var{mountpoint} +mount the filesystem locally as the name given, in case this is +different from the advertised volume name of the filesystem. + +@item opts @var{options} +native @b{mount}(8) options. + +@item fstype @var{type} +type of filesystem to be mounted. +@end table + +An example: + +@example +mount /export/exec/hp300/local as /usr/local +@end example + +If the mountpoint specified is either @file{/} or @file{swap}, the +machine will be considered to be booting off the net and this will be +noted for use in generating a @file{bootparams} file for the host which +owns the filesystems. + +@node FSinfo automount definitions, FSinfo Command Line Options, FSinfo static mounts, FSinfo +@comment node-name, next, previous, up +@section Defining an @i{Amd} Mount Map in @i{FSinfo} +@cindex FSinfo automount definitions +@cindex Defining an Amd mount map, FSinfo + +The maps used by @i{Amd} can be constructed from @i{FSinfo} by defining +all the automount trees. @i{FSinfo} takes all the definitions found and +builds one map for each top level tree. + +The automount tree is usually defined last. A single automount +configuration will usually apply to an entire management domain. One +@code{automount} declaration is needed for each @i{Amd} automount point. +@i{FSinfo} determines whether the automount point is @dfn{direct} +(@pxref{Direct Automount Filesystem}) or @dfn{indirect} +(@pxref{Top-level Filesystem}). Direct automount points are +distinguished by the fact that there is no underlying +@dfn{automount_tree}.@refill + +@example +automount : "automount" @i{opt(}auto_opts@i{)} automount_tree ; + +auto_opts : "opts" @var{<mount-options>} ; + +automount_tree + : @i{list(}automount_attr@i{)} + ; + +automount_attr + : @var{<string>} "=" @var{<volname>} + | @var{<string>} "->" @var{<symlink>} + | @var{<string>} "@{" automount_tree "@}" + ; +@end example + +If @var{<mount-options>} is given, then it is the string to be placed in +the maps for @i{Amd} for the @code{opts} option. + +A @dfn{map} is typically a tree of filesystems, for example @file{home} +normally contains a tree of filesystems representing other machines in +the network. + +A map can either be given as a name representing an already defined +volume name, or it can be a tree. A tree is represented by placing +braces after the name. For example, to define a tree @file{/vol}, the +following map would be defined: + +@example +automount /vol @{ @} +@end example + +Within a tree, the only items that can appear are more maps. +For example: + +@example +automount /vol @{ + andrew @{ @} + X11 @{ @} +@} +@end example + +In this case, @i{FSinfo} will look for volumes named @file{/vol/andrew} +and @file{/vol/X11} and a map entry will be generated for each. If the +volumes are defined more than once, then @i{FSinfo} will generate +a series of alternate entries for them in the maps.@refill + +Instead of a tree, either a link (@var{name} @code{->} +@var{destination}) or a reference can be specified (@var{name} @code{=} +@var{destination}). A link creates a symbolic link to the string +specified, without further processing the entry. A reference will +examine the destination filesystem and optimize the reference. For +example, to create an entry for @code{njw} in the @file{/homes} map, +either of the two forms can be used:@refill + +@example +automount /homes @{ + njw -> /home/dylan/njw +@} +@end example + +or + +@example +automount /homes @{ + njw = /home/dylan/njw +@} +@end example + +In the first example, when @file{/homes/njw} is referenced from @i{Amd}, +a link will be created leading to @file{/home/dylan/njw} and the +automounter will be referenced a second time to resolve this filename. +The map entry would be: + +@example +njw type:=link;fs:=/home/dylan/njw +@end example + +In the second example, the destination directory is analyzed and found +to be in the filesystem @file{/home/dylan} which has previously been +defined in the maps. Hence the map entry will look like: + +@example +njw rhost:=dylan;rfs:=/home/dylan;sublink:=njw +@end example + +Creating only one symbolic link, and one access to @i{Amd}. + +@node FSinfo Command Line Options, FSinfo errors, FSinfo automount definitions, FSinfo +@comment node-name, next, previous, up +@section @i{FSinfo} Command Line Options +@cindex FSinfo command line options +@cindex Command line options, FSinfo + +@i{FSinfo} is started from the command line by using the command: + +@example +fsinfo [@i{options}] @i{files} ... +@end example + +The input to @i{FSinfo} is a single set of definitions of machines and +automount maps. If multiple files are given on the command-line, then +the files are concatenated together to form the input source. The files +are passed individually through the C pre-processor before being parsed. + +Several options define a prefix for the name of an output file. If the +prefix is not specified no output of that type is produced. The suffix +used will correspond either to the hostname to which a file belongs, or +to the type of output if only one file is produced. Dumpsets and the +@file{bootparams} file are in the latter class. To put the output into +a subdirectory simply put a @file{/} at the end of the prefix, making +sure that the directory has already been made before running +@i{Fsinfo}. + +@menu +* -a FSinfo Option:: Amd automount directory: +* -b FSinfo Option:: Prefix for bootparams files. +* -d FSinfo Option:: Prefix for dumpset data files. +* -e FSinfo Option:: Prefix for exports files. +* -f FSinfo Option:: Prefix for fstab files. +* -h FSinfo Option:: Local hostname. +* -m FSinfo Option:: Prefix for automount maps. +* -q FSinfo Option:: Ultra quiet mode. +* -v FSinfo Option:: Verbose mode. +* -I FSinfo Option:: Define new #include directory. +* -D-FSinfo Option:: Define macro. +* -U FSinfo Option:: Undefine macro. +@end menu + +@node -a FSinfo Option, -b FSinfo Option, FSinfo Command Line Options, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-a} @var{autodir} + +Specifies the directory name in which to place the automounter's +mountpoints. This defaults to @file{/a}. Some sites have the autodir set +to be @file{/amd}, and this would be achieved by: + +@example +fsinfo -a /amd ... +@end example + +@node -b FSinfo Option, -d FSinfo Option, -a FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-b} @var{bootparams} +@cindex bootparams, FSinfo prefix + +This specifies the prefix for the @file{bootparams} filename. If it is +not given, then the file will not be generated. The @file{bootparams} +file will be constructed for the destination machine and will be placed +into a file named @file{bootparams} and prefixed by this string. The +file generated contains a list of entries describing each diskless +client that can boot from the destination machine. + +As an example, to create a @file{bootparams} file in the directory +@file{generic}, the following would be used: + +@example +fsinfo -b generic/ ... +@end example + +@node -d FSinfo Option, -e FSinfo Option, -b FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-d} @var{dumpsets} +@cindex dumpset, FSinfo prefix + +This specifies the prefix for the @file{dumpsets} file. If it is not +specified, then the file will not be generated. The file will be for +the destination machine and will be placed into a filename +@file{dumpsets}, prefixed by this string. The @file{dumpsets} file is +for use by Imperial College's local backup system. + +For example, to create a @file{dumpsets} file in the directory @file{generic}, +then you would use the following: + +@example +fsinfo -d generic/ ... +@end example + +@node -e FSinfo Option, -f FSinfo Option, -d FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-e} @var{exportfs} +@cindex exports, FSinfo prefix + +Defines the prefix for the @file{exports} files. If it is not given, +then the file will not be generated. For each machine defined in the +configuration files as having disks, an @file{exports} file is +constructed and given a filename determined by the name of the machine, +prefixed with this string. If a machine is defined as diskless, then no +@file{exports} file will be created for it. The files contain entries +for directories on the machine that may be exported to clients. + +Example: To create the @file{exports} files for each diskfull machine +and place them into the directory @file{exports}: + +@example +fsinfo -e exports/ ... +@end example + +@node -f FSinfo Option, -h FSinfo Option, -e FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-f} @var{fstab} +@cindex fstab, FSinfo prefix + +This defines the prefix for the @file{fstab} files. The files will only +be created if this prefix is defined. For each machine defined in the +configuration files, a @file{fstab} file is created with the filename +determined by prefixing this string with the name of the machine. These +files contain entries for filesystems and partitions to mount at boot +time. + +Example, to create the files in the directory @file{fstabs}: + +@example +fsinfo -f fstabs/ ... +@end example + +@node -h FSinfo Option, -m FSinfo Option, -f FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-h} @var{hostname} +@cindex hostname, FSinfo command line option + +Defines the hostname of the destination machine to process for. If this +is not specified, it defaults to the local machine name, as returned by +@b{gethostname}(2). + +Example: + +@example +fsinfo -h dylan.doc.ic.ac.uk ... +@end example + +@node -m FSinfo Option, -q FSinfo Option, -h FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-m} @var{mount-maps} +@cindex maps, FSinfo command line option + +Defines the prefix for the automounter files. The maps will only be +produced if this prefix is defined. The mount maps suitable for the +network defined by the configuration files will be placed into files +with names calculated by prefixing this string to the name of each map. + +For example, to create the automounter maps and place them in the +directory @file{automaps}: + +@example +fsinfo -m automaps/ ... +@end example + +@node -q FSinfo Option, -v FSinfo Option, -m FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-q} +@cindex quiet, FSinfo command line option + +Selects quiet mode. @i{FSinfo} suppress the ``running commentary'' and +only outputs any error messages which are generated. + +@node -v FSinfo Option, -D-FSinfo Option, -q FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-v} +@cindex verbose, FSinfo command line option + +Selects verbose mode. When this is activated, the program will display +more messages, and display all the information discovered when +performing the semantic analysis phase. Each verbose message is output +to @file{stdout} on a line starting with a @samp{#} character. + +@node -D-FSinfo Option, -I FSinfo Option, -v FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-D} @var{name[=defn]} + +Defines a symbol @dfn{name} for the preprocessor when reading the +configuration files. Equivalent to @code{#define} directive. + +@node -I FSinfo Option, -U FSinfo Option, -D-FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-I} @var{directory} + +This option is passed into the preprocessor for the configuration files. +It specifies directories in which to find include files + +@node -U FSinfo Option, , -I FSinfo Option, FSinfo Command Line Options +@comment node-name, next, previous, up +@subsection @code{-U} @var{name} + +Removes any initial definition of the symbol @dfn{name}. Inverse of the +@code{-D} option. + +@node FSinfo errors, , FSinfo Command Line Options, FSinfo +@comment node-name, next, previous, up +@section Errors produced by @i{FSinfo} +@cindex FSinfo error messages + +The following table documents the errors and warnings which @i{FSinfo} may produce. + +@table @t + +@item " expected +Occurs if an unescaped newline is found in a quoted string. + +@item ambiguous mount: @var{volume} is a replicated filesystem +If several filesystems are declared as having the same volume name, they +will be considered replicated filesystems. To mount a replicated +filesystem statically, a specific host will need to be named, to say +which particular copy to try and mount, else this error will +result. + +@item can't open @var{filename} for writing +Occurs if any errors are encountered when opening an output file. + +@item cannot determine localname since volname @var{volume} is not uniquely defined +If a volume is replicated and an attempt is made to mount the filesystem +statically without specifying a local mountpoint, @i{FSinfo} cannot +calculate a mountpoint, as the desired pathname would be +ambiguous. + +@item @var{device} has duplicate exportfs data +Produced if the @samp{exportfs} option is used multiple times within the +same branch of a filesystem definition. For example, if you attempt to +set the @samp{exportfs} data at different levels of the mountpoint +directory tree. + +@item dump frequency for @var{host}:@var{device} is non-zero +Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap} +or @samp{export} and the @samp{dump} option is set to a value greater +than zero. Swap devices should not be dumped. + +@item duplicate host @var{hostname}! +If a host has more than one definition. + +@item end of file within comment +A comment was unterminated before the end of one of the configuration +files. + +@item @var{filename}: cannot open for reading +If a file specified on the command line as containing configuration data +could not be opened. + +@item @var{filesystem} has a volname but no exportfs data +Occurs when a volume name is declared for a file system, but the string +specifying what machines the filesystem can be exported to is +missing. + +@item fs field "@var{field-name}" already set +Occurs when multiple definitions are given for one of the attributes of a +host's filesystem. + +@item host field "@var{field-name}" already set +If duplicate definitions are given for any of the fields with a host +definition. + +@item @var{host}:@var{device} has more than one mount point +Occurs if the mount option for a host's filesystem specifies multiple +trees at which to place the mountpoint. + +@item @var{host}:@var{device} has no mount point +Occurs if the @samp{mount} option is not specified for a host's +filesystem. + +@item @var{host}:@var{device} needs field "@var{field-name}" +Occurs when a filesystem is missing a required field. @var{field-name} could +be one of @samp{fstype}, @samp{opts}, @samp{passno} or +@samp{mount}. + +@item @var{host}:mount field specified for swap partition +Occurs if a mountpoint is given for a filesystem whose type is declared +to be @samp{swap}. + +@item malformed IP dotted quad: @var{address} +If the Internet address of an interface is incorrectly specified. An +Internet address definition is handled to @b{inet_addr}(3N) to see if it +can cope. If not, then this message will be displayed. + +@item malformed netmask: @var{netmask} +If the netmask cannot be decoded as though it were a hexadecimal number, +then this message will be displayed. It will typically be caused by +incorrect characters in the @var{netmask} value. + +@item mount field "@var{field-name}" already set +Occurs when a static mount has multiple definitions of the same field. + +@item mount tree field "@var{field-name}" already set +Occurs when the @var{field-name} is defined more than once during the +definition of a filesystems mountpoint. + +@item netif field @var{field-name} already set +Occurs if you attempt to define an attribute of an interface more than +once. + +@item network booting requires both root and swap areas +Occurs if a machine has mount declarations for either the root partition +or the swap area, but not both. You cannot define a machine to only +partially boot via the network. + +@item no disk mounts on @var{hostname} +If there are no static mounts, nor local disk mounts specified for a +machine, this message will be displayed. + +@item no volname given for @var{host}:@var{device} +Occurs when a filesystem is defined to be mounted on @file{default}, but +no volume name is given for the file system, then the mountpoint cannot +be determined. + +@item not allowed '/' in a directory name +Occurs when a pathname with multiple directory elements is specified as +the name for an automounter tree. A tree should only have one name at +each level. + +@item pass number for @var{host}:@var{device} is non-zero +Occurs if @var{device} has its @samp{fstype} declared to be @samp{swap} +or @samp{export} and the @b{fsck}(8) pass number is set. Swap devices should not be +fsck'd. @xref{FSinfo filesystems fstype}. + +@item sub-directory @var{directory} of @var{directory-tree} starts with '/' +Within the filesystem specification for a host, if an element +@var{directory} of the mountpoint begins with a @samp{/} and it is not +the start of the tree. + +@item sub-directory of @var{directory-tree} is named "default" +@samp{default} is a keyword used to specify if a mountpoint should be +automatically calculated by @i{FSinfo}. If you attempt to specify a +directory name as this, it will use the filename of @file{default} but +will produce this warning. + +@item unknown \ sequence +Occurs if an unknown escape sequence is found inside a string. Within a +string, you can give the standard C escape sequences for strings, such +as newlines and tab characters. + +@item unknown directory attribute +If an unknown keyword is found while reading the definition of a host's +filesystem mount option. + +@item unknown filesystem attribute +Occurs if an unrecognized keyword is used when defining a host's +filesystems. + +@item unknown host attribute +Occurs if an unrecognized keyword is used when defining a host. + +@item unknown mount attribute +Occurs if an unrecognized keyword is found while parsing the list of +static mounts. + +@item unknown volname @var{volume} automounted @i{[} on @i{name} @i{]} +Occurs if @var{volume} is used in a definition of an automount map but the volume +name has not been declared during the host filesystem definitions. + +@item volname @var{volume} is unknown +Occurs if an attempt is made to mount or reference a volume name which +has not been declared during the host filesystem definitions. + +@item volname @var{volume} not exported from @var{machine} +Occurs if you attempt to mount the volume @var{volume} from a machine +which has not declared itself to have such a filesystem +available. + +@end table + +@c ################################################################ +@node Hlfsd, Assorted Tools, FSinfo, Top +@comment node-name, next, previous, up +@chapter Hlfsd +@pindex Hlfsd +@cindex Home-Link Filesystem + +@i{Hlfsd} is a daemon which implements a filesystem containing a +symbolic link to subdirectory within a user's home directory, depending +on the user which accessed that link. It was primarily designed to +redirect incoming mail to users' home directories, so that it can be read +from anywhere. It was designed and implemented by +@email{ezk@@cs.columbia.edu,Erez Zadok} and +@email{dupuy@@cs.columbia.edu,Alexander Dupuy}, at the +@uref{http://www.cs.columbia.edu/,Computer Science Department} of +@uref{http://www.columbia.edu/,Columbia University}. A +@uref{http://www.cs.columbia.edu/~ezk/research/hlfsd/hlfsd.html,paper} +on @i{Hlfsd} was presented at the Usenix LISA VII conference in 1993. + +@i{Hlfsd} operates by mounting itself as an NFS server for the directory +containing @i{linkname}, which defaults to @file{/hlfs/home}. Lookups +within that directory are handled by @i{Hlfsd}, which uses the +password map to determine how to resolve the lookup. The directory will +be created if it doesn't already exist. The symbolic link will be to +the accessing user's home directory, with @i{subdir} appended to it. If +not specified, @i{subdir} defaults to @file{.hlfsdir}. This directory +will also be created if it does not already exist. + +A @samp{SIGTERM} sent to @i{Hlfsd} will cause it to shutdown. A @samp{SIGHUP} will +flush the internal caches, and reload the password map. It will also +close and reopen the log file, to enable the original log file to be +removed or rotated. A @samp{SIGUSR1} will cause it to dump its internal table +of user IDs and home directories to the file @file{/tmp/hlfsddump}. + +@menu +* Introduction to Hlfsd:: +* Background to Mail Delivery:: +* Using Hlfsd:: +@end menu + +@c ================================================================ +@node Introduction to Hlfsd, Background to Mail Delivery, Hlfsd, Hlfsd +@comment node-name, next, previous, up +@section Introduction to Hlfsd +@cindex Introduction to Hlfsd +@cindex Hlfsd; introduction + +Electronic mail has become one of the major applications for many +computer networks, and use of this service is expected to increase over +time, as networks proliferate and become faster. Providing a convenient +environment for users to read, compose, and send electronic mail has +become a requirement for systems administrators (SAs). + +Widely used methods for handling mail usually require users to be logged +into a designated ``home'' machine, where their mailbox files reside. +Only on that one machine can they read newly arrived mail. Since users +have to be logged into that system to read their mail, they often find +it convenient to run all of their other processes on that system as +well, including memory and CPU-intensive jobs. For example, in our +department, we have allocated and configured several multi-processor +servers to handle such demanding CPU/memory applications, but these were +underutilized, in large part due to the inconvenience of not being able +to read mail on those machines. (No home directories were located on +these designated CPU-servers, since we did not want NFS service for +users' home directories to have to compete with CPU-intensive jobs. At the +same time, we discouraged users from running demanding applications on +their home machines.) + +Many different solutions have been proposed to allow users to read their +mail on any host. However, all of these solutions fail in one or more +of several ways: + +@itemize @bullet + +@item +they introduce new single points of failure + +@item +they require using different mail transfer agents (MTAs) or user agents +(UAs) + +@item +they do not solve the problem for all cases, i.e. the solution is only +partially successful for a particular environment. + +@end itemize + +We have designed a simple filesystem, called the @dfn{Home-Link File +System}, to provide the ability to deliver mail to users' home +directories, without modification to mail-related applications. We have +endeavored to make it as stable as possible. Of great importance to us +was to make sure the HLFS daemon, @file{hlfsd} , would not hang under +any circumstances, and would take the next-best action when faced with +problems. Compared to alternative methods, @i{Hlfsd} is a stable, more +general solution, and easier to install/use. In fact, in some ways, we +have even managed to improve the reliability and security of mail +service. + +Our server implements a small filesystem containing a symbolic link +to a subdirectory of the invoking user's home directory, and named symbolic +links to users' mailbox files. + +The @i{Hlfsd} server finds out the @var{uid} of the process that is +accessing its mount point, and resolves the pathname component @samp{home} as a +symbolic link to a subdirectory within the home directory given by the +@var{uid}'s entry in the password file. If the @var{gid} of the process +that attempts to access a mailbox file is a special one (called +HLFS_GID), then the server maps the name of the @emph{next} pathname +component directly to the user's mailbox. This is necessary so that +access to a mailbox file by users other than the owner can succeed. The +server has safety features in case of failures such as hung filesystems +or home directory filesystems that are inaccessible or full. + +On most of our machines, mail gets delivered to the directory +@file{/var/spool/mail}. Many programs, including UAs, depend on that +path. @i{Hlfsd} creates a directory @file{/mail}, and mounts itself on +top of that directory. @i{Hlfsd} implements the path name component +called @samp{home}, pointing to a subdirectory of the user's home directory. +We have made @file{/var/spool/mail} a symbolic link to +@file{/mail/home}, so that accessing @file{/var/spool/mail} actually +causes access to a subdirectory within a user's home directory. + +The following table shows an example of how resolving the pathname +@file{/var/mail/@i{NAME}} to @file{/users/ezk/.mailspool/@i{NAME}} proceeds. + +@multitable {Resolving Component} {Pathname left to resolve} {Value if symbolic link} + +@item @b{Resolving Component} +@tab @b{Pathname left to resolve} +@tab @b{Value if symbolic link} + +@item @t{/} +@tab @t{var/mail/}@i{NAME} + +@item @t{var/} +@tab @t{mail/}@i{NAME} + +@item @t{mail}@@ +@tab @t{/mail/home/}@i{NAME} +@tab @t{mail}@@ -> @t{/mail/home} + +@item @t{/} +@tab @t{mail/home/}@i{NAME} + +@item @t{mail/} +@tab @t{home/}@i{NAME} + +@item @t{home}@@ +@tab @i{NAME} +@tab @t{home}@@ -> @t{/users/ezk/.mailspool} + +@item @t{/} +@tab @t{users/ezk/.mailspool/}@i{NAME} + +@item @t{users/} +@tab @t{ezk/.mailspool/}@i{NAME} + +@item @t{ezk/} +@tab @t{.mailspool/}@i{NAME} + +@item @t{.mailspool/} +@tab @i{NAME} + +@item @i{NAME} + +@end multitable + +@c ================================================================ +@node Background to Mail Delivery, Using Hlfsd, Introduction to Hlfsd, Hlfsd +@comment node-name, next, previous, up +@section Background to Mail Delivery +@cindex Background to Mail Delivery +@cindex Hlfsd; background + +This section provides an in-depth discussion of why available methods +for delivering mail to home directories are not as good as the one used +by @i{Hlfsd}. + +@menu +* Single-Host Mail Spool Directory:: +* Centralized Mail Spool Directory:: +* Distributed Mail Spool Service:: +* Why Deliver Into the Home Directory?:: +@end menu + +@c ---------------------------------------------------------------- +@node Single-Host Mail Spool Directory, Centralized Mail Spool Directory, Background to Mail Delivery, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Single-Host Mail Spool Directory +@cindex Single-Host Mail Spool Directory + +The most common method for mail delivery is for mail to be appended to a +mailbox file in a standard spool directory on the designated ``mail +home'' machine of the user. The greatest advantage of this method is +that it is the default method most vendors provide with their systems, +thus very little (if any) configuration is required on the SA's part. +All they need to set up are mail aliases directing mail to the host on +which the user's mailbox file is assigned. (Otherwise, mail is +delivered locally, and users find mailboxes on many machines.) + +As users become more sophisticated, and aided by windowing systems, they +find themselves logging in on multiple hosts at once, performing several +tasks concurrently. They ask to be able to read their mail on any host +on the network, not just the one designated as their ``mail home''. + +@c ---------------------------------------------------------------- +@node Centralized Mail Spool Directory, Distributed Mail Spool Service, Single-Host Mail Spool Directory, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Centralized Mail Spool Directory +@cindex Centralized Mail Spool Directory + +A popular method for providing mail readability from any host is to have +all mail delivered to a mail spool directory on a designated +``mail-server'' which is exported via NFS to all of the hosts on the +network. Configuring such a system is relatively easy. On most +systems, the bulk of the work is a one-time addition to one or two +configuration files in @file{/etc}. The file-server's spool directory +is then hard-mounted across every machine on the local network. In +small environments with only a handful of hosts this can be an +acceptable solution. In our department, with a couple of hundred active +hosts and thousands of mail messages processed daily, this was deemed +completely unacceptable, as it introduced several types of problems: + +@table @b + +@item Scalability and Performance + +As more and more machines get added to the network, more mail traffic +has to go over NFS to and from the mail-server. Users like to run +mail-watchers, and read their mail often. The stress on the shared +infrastructure increases with every user and host added; loads on the +mail server would most certainly be high since all mail delivery goes +through that one machine.@footnote{ Delivery via NFS-mounted filesystems +may require usage of @samp{rpc.lockd} and @samp{rpc.statd} to provide +distributed file-locking, both of which are widely regarded as unstable +and unreliable. Furthermore, this will degrade performance, as local +processes as well as remote @samp{nfsd} processes are kept busy.} This +leads to lower reliability and performance. To reduce the number of +concurrent connections between clients and the server host, some SAs +have resorted to automounting the mail-spool directory. But this +solution only makes things worse: since users often run mail watchers, +and many popular applications such as @samp{trn}, @samp{emacs}, +@samp{csh} or @samp{ksh} check periodically for new mail, the +automounted directory would be effectively permanently mounted. If it +gets unmounted automatically by the automounter program, it is most +likely to get mounted shortly afterwards, consuming more I/O resources +by the constant cycle of mount and umount calls. + +@item Reliability + +The mail-server host and its network connectivity must be very reliable. +Worse, since the spool directory has to be hard-mounted,@footnote{No SA +in their right minds would soft-mount read/write partitions --- the +chances for data loss are too great.} many processes which access the +spool directory (various shells, @samp{login}, @samp{emacs}, etc.) +would be hung as long as connectivity to the mail-server is severed. To +improve reliability, SAs may choose to backup the mail-server's spool +partition several times a day. This may make things worse since reading +or delivering mail while backups are in progress may cause backups to be +inconsistent; more backups consume more backup-media resources, and +increase the load on the mail-server host. + +@end table + +@c ---------------------------------------------------------------- +@node Distributed Mail Spool Service, Why Deliver Into the Home Directory?, Centralized Mail Spool Directory, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Distributed Mail Spool Service +@cindex Distributed Mail Spool Service + +Despite the existence of a few systems that support delivery to users' +home directories, mail delivery to home directories hasn't caught on. +We believe the main reason is that there are too many programs that +``know'' where mailbox files reside. Besides the obvious (the delivery +program @file{/bin/mail} and mail readers like @file{/usr/ucb/Mail}, +@samp{mush}, @samp{mm}, etc.), other programs that know mailbox location +are login, from, almost every shell, @samp{xbiff}, @samp{xmailbox}, and +even some programs not directly related to mail, such as @samp{emacs} +and @samp{trn}. Although some of these programs can be configured to +look in different directories with the use of environment variables and +other resources, many of them cannot. The overall porting work is +significant. + +Other methods that have yet to catch on require the use of a special +mail-reading server, such as IMAP or POP. The main disadvantage of +these systems is that UAs need to be modified to use these services --- +a long and involved task. That is why they are not popular at this +time. + +Several other ideas have been proposed and even used in various +environments. None of them is robust. They are mostly very +specialized, inflexible, and do not extend to the general case. Some of +the ideas are plain bad, potentially leading to lost or corrupt mail: + +@table @b + +@item automounters + +Using an automounter such as @i{Amd} to provide a set of symbolic links +from the normal spool directory to user home directories is not +sufficient. UAs rename, unlink, and recreate the mailbox as a regular +file, therefore it must be a real file, not a symbolic link. +Furthermore, it must reside in a real directory which is writable by the +UAs and MTAs. This method may also require populating +@file{/var/spool/mail} with symbolic links and making sure they are +updated. Making @i{Amd} manage that directory directly fails, since +many various lock files need to be managed as well. Also, @i{Amd} does +not provide all of the NFS operations which are required to write mail +such as write, create, remove, and unlink. + +@item @code{$MAIL} + +Setting this variable to an automounted directory pointing to the user's +mail spool host only solves the problem for those programs which know +and use @code{$MAIL}. Many programs don't, therefore this solution is partial +and of limited flexibility. Also, it requires the SAs or the users to +set it themselves --- an added level of inconvenience and possible +failures. + +@item @t{/bin/mail} + +Using a different mail delivery agent could be the solution. One such +example is @samp{hdmail}. However, @samp{hdmail} still requires +modifying all UAs, the MTA's configuration, installing new daemons, and +changing login scripts. This makes the system less upgradable or +compatible with others, and adds one more complicated system for SAs to +deal with. It is not a complete solution because it still requires each +user have their @code{$MAIL} variable setup correctly, and that every program +use this variable. + +@end table + +@c ---------------------------------------------------------------- +@node Why Deliver Into the Home Directory?, , Distributed Mail Spool Service, Background to Mail Delivery +@comment node-name, next, previous, up +@subsection Why Deliver Into the Home Directory? +@cindex Why Deliver Into the Home Directory? +@cindex Hlfsd; Why Deliver Into the Home Directory? + +There are several major reasons why SAs might want to deliver mail +directly into the users' home directories: + +@table @b + +@item Location + +Many mail readers need to move mail from the spool directory to the +user's home directory. It speeds up this operation if the two are on +the same filesystem. If for some reason the user's home directory is +inaccessible, it isn't that useful to be able to read mail, since there +is no place to move it to. In some cases, trying to move mail to a +non-existent or hung filesystem may result in mail loss. + +@item Distribution + +Having all mail spool directories spread among the many more filesystems +minimizes the chances that complete environments will grind to a halt +when a single server is down. It does increase the chance that there +will be someone who is not able to read their mail when a machine is +down, but that is usually preferred to having no one be able to read +their mail because a centralized mail server is down. The problem of +losing some mail due to the (presumably) higher chances that a user's +machine is down is minimized in HLFS. + +@item Security + +Delivering mail to users' home directories has another advantage --- +enhanced security and privacy. Since a shared system mail spool +directory has to be world-readable and searchable, any user can see +whether other users have mail, when they last received new mail, or when +they last read their mail. Programs such as @samp{finger} display this +information, which some consider an infringement of privacy. While it +is possible to disable this feature of @samp{finger} so that remote +users cannot see a mailbox file's status, this doesn't prevent local +users from getting the information. Furthermore, there are more +programs which make use of this information. In shared environments, +disabling such programs has to be done on a system-wide basis, but with +mail delivered to users' home directories, users less concerned with +privacy who do want to let others know when they last received or read +mail can easily do so using file protection bits. + +@c Lastly, on systems that do not export their NFS filesystem with +@c @t{anon=0}, superusers are less likely to snoop around others' mail, as +@c they become ``nobodies'' across NFS. + +@end table + +In summary, delivering mail to home directories provides users the +functionality sought, and also avoids most of the problems just +discussed. + +@c ================================================================ +@node Using Hlfsd, , Background to Mail Delivery, Hlfsd +@comment node-name, next, previous, up +@section Using Hlfsd +@cindex Using Hlfsd +@cindex Hlfsd; using + +@menu +* Controlling Hlfsd:: +* Hlfsd Options:: +* Hlfsd Files:: +@end menu + +@c ---------------------------------------------------------------- +@node Controlling Hlfsd, Hlfsd Options, Using Hlfsd, Using Hlfsd +@comment node-name, next, previous, up +@subsection Controlling Hlfsd +@cindex Controlling Hlfsd +@cindex Hlfsd; controlling +@pindex ctl-hlfsd + +Much the same way @i{Amd} is controlled by @file{ctl-amd}, so does +@i{Hlfsd} get controlled by the @file{ctl-hlfsd} script: + +@table @t + +@item ctl-hlfsd start +Start a new @i{Hlfsd}. + +@item ctl-hlfsd stop +Stop a running @i{Hlfsd}. + +@item ctl-hlfsd restart +Stop a running @i{Hlfsd}, wait for 10 seconds, and then start a new +one. It is hoped that within 10 seconds, the previously running +@i{Hlfsd} terminate properly; otherwise, starting a second one could +cause system lockup. + +@end table + +For example, on our systems, we start @i{Hlfsd} within @file{ctl-hlfsd} +as follows on Solaris 2 systems: + +@example +hlfsd -a /var/alt_mail -x all -l /var/log/hlfsd /mail/home .mailspool +@end example + +The directory @file{/var/alt_mail} is a directory in the root partition +where alternate mail will be delivered into, when it cannot be delivered +into the user's home directory. + +Normal mail gets delivered into @file{/var/mail}, but on our systems, +that is a symbolic link to @file{/mail/home}. @file{/mail} is managed +by @i{Hlfsd}, which creates a dynamic symlink named @samp{home}, +pointing to the subdirectory @file{.mailspool} @emph{within} the +accessing user's home directory. This results in mail which normally +should go to @file{/var/mail/@code{$USER}}, to go to +@file{@code{$HOME}/.mailspool/@code{$USER}}. + +@i{Hlfsd} does not create the @file{/var/mail} symlink. This needs to +be created (manually) once on each host, by the system administrators, +as follows: + +@example +mv /var/mail /var/alt_mail +ln -s /mail/home /var/mail +@end example + +@c ---------------------------------------------------------------- +@node Hlfsd Options, Hlfsd Files, Controlling Hlfsd, Using Hlfsd +@comment node-name, next, previous, up +@subsection Hlfsd Options +@cindex Hlfsd Options +@cindex Hlfsd; Options + +@table @t + +@item -a @var{alt_dir} +Alternate directory. The name of the directory to which the symbolic +link returned by @i{Hlfsd} will point, if it cannot access the home +directory of the user. This defaults to @file{/var/hlfs}. This +directory will be created if it doesn't exist. It is expected that +either users will read these files, or the system administrators will +run a script to resend this ``lost mail'' to its owner. + +@item -c @var{cache-interval} +Caching interval. @i{Hlfsd} will cache the validity of home directories +for this interval, in seconds. Entries which have been verified within +the last @var{cache-interval} seconds will not be verified again, since +the operation could be expensive, and the entries are most likely still +valid. After the interval has expired, @i{Hlfsd} will re-verify the +validity of the user's home directory, and reset the cache time-counter. +The default value for @var{cache-interval} is 300 seconds (5 minutes). + +@item -f +Force fast startup. This option tells @i{Hlfsd} to skip startup-time +consistency checks such as existence of mount directory, alternate spool +directory, symlink to be hidden under the mount directory, their +permissions and validity. + +@item -g @var{group} +Set the special group HLFS_GID to @var{group}. Programs such as +@file{/usr/ucb/from} or @file{/usr/sbin/in.comsat}, which access the +mailboxes of other users, must be setgid @samp{HLFS_GID} to work properly. The +default group is @samp{hlfs}. If no group is provided, and there is no +group @samp{hlfs}, this feature is disabled. + +@item -h +Help. Print a brief help message, and exit. + +@item -i @var{reload-interval} +Map-reloading interval. Each @var{reload-interval} seconds, @i{Hlfsd} +will reload the password map. @i{Hlfsd} needs the password map for the +UIDs and home directory pathnames. @i{Hlfsd} schedules a @samp{SIGALRM} to +reload the password maps. A @samp{SIGHUP} sent to @i{Hlfsd} will force it to +reload the maps immediately. The default value for +@var{reload-interval} is 900 seconds (15 minutes.) + +@item -l @var{logfile} +Specify a log file to which @i{Hlfsd} will record events. If +@var{logfile} is the string @samp{syslog} then the log messages will be +sent to the system log daemon by @b{syslog}(3), using the @samp{LOG_DAEMON} +facility. This is also the default. + +@item -n +No verify. @i{Hlfsd} will not verify the validity of the symbolic link +it will be returning, or that the user's home directory contains +sufficient disk-space for spooling. This can speed up @i{Hlfsd} at the +cost of possibly returning symbolic links to home directories which are +not currently accessible or are full. By default, @i{Hlfsd} validates +the symbolic-link in the background. The @code{-n} option overrides the +meaning of the @code{-c} option, since no caching is necessary. + +@item -o @var{mount-options} +Mount options which @i{Hlfsd} will use to mount itself on top of +@var{dirname}. By default, @var{mount-options} is set to @samp{ro}. If +the system supports symbolic-link caching, default options are set +to @samp{ro,nocache}. + +@item -p +Print PID. Outputs the process-id of @i{Hlfsd} to standard output where +it can be saved into a file. + +@item -v +Version. Displays version information to standard error. + +@item -x @var{log-options} +Specify run-time logging options. The options are a comma separated +list chosen from: @samp{fatal}, @samp{error}, @samp{user}, @samp{warn}, @samp{info}, @samp{map}, @samp{stats}, @samp{all}. + +@item -C +Force @i{Hlfsd} to run on systems that cannot turn off the NFS +attribute-cache. Use of this option on those systems is discouraged, as +it may result in loss or misdelivery of mail. The option is ignored on +systems that can turn off the attribute-cache. + +@item -D @var{log-options} +Select from a variety of debugging options. Prefixing an option with +the string @samp{no} reverses the effect of that option. Options are +cumulative. The most useful option is @samp{all}. Since this option is +only used for debugging other options are not documented here. A fuller +description is available in the program source. A @samp{SIGUSR1} sent +to @i{Hlfsd} will cause it to dump its internal password map to the file +@file{/usr/tmp/hlfsd.dump.XXXXXX}, where @samp{XXXXXX} will be replaced +by a random string generated by @b{mktemp}(3) or (the more secure) +@b{mkstemp}(3). + +@item -P @var{password-file} +Read the user-name, user-id, and home directory information from the +file @var{password-file}. Normally, @i{Hlfsd} will use @b{getpwent}(3) +to read the password database. This option allows you to override the +default database, and is useful if you want to map users' mail files to +a directory other than their home directory. Only the username, uid, +and home-directory fields of the file @var{password-file} are read and +checked. All other fields are ignored. The file @var{password-file} +must otherwise be compliant with Unix Version 7 colon-delimited format +@b{passwd}(4). + +@end table + +@c ---------------------------------------------------------------- +@node Hlfsd Files, , Hlfsd Options, Using Hlfsd +@comment node-name, next, previous, up +@subsection Hlfsd Files +@cindex Hlfsd Files +@cindex Hlfsd; Files + +The following files are used by @i{Hlfsd}: + +@table @file + +@item /hlfs +directory under which @i{Hlfsd} mounts itself and manages the symbolic +link @file{home}. + +@item .hlfsdir +default sub-directory in the user's home directory, to which the +@file{home} symbolic link returned by @i{Hlfsd} points. + +@item /var/hlfs +directory to which @file{home} symbolic link returned by @i{Hlfsd} +points if it is unable to verify the that user's home directory is +accessible. + +@end table + +For discussion on other files used by @i{Hlfsd}, see @ref{lostaltmail} and +@ref{lostaltmail.conf-sample}. + +@c ################################################################ +@node Assorted Tools, Examples, Hlfsd, Top +@comment node-name, next, previous, up +@chapter Assorted Tools +@cindex Assorted Tools + +The following are additional utilities and scripts included with +am-utils, and get installed. + +@menu +* am-eject:: +* amd.conf-sample:: +* amd2ldif:: +* amd2sun:: +* ctl-amd:: +* ctl-hlfsd:: +* expn:: +* fix-amd-map:: +* fixmount:: +* fixrmtab:: +* lostaltmail:: +* lostaltmail.conf-sample:: +* mk-amd-map:: +* pawd:: +* wait4amd:: +* wait4amd2die:: +* wire-test:: +@end menu + +@c ---------------------------------------------------------------- +@node am-eject, amd.conf-sample, Assorted Tools, Assorted Tools +@comment node-name, next, previous, up +@section am-eject +@pindex am-eject + +A shell script unmounts a floppy or CD-ROM that is automounted, and +then attempts to eject the removable device. + +@c ---------------------------------------------------------------- +@node amd.conf-sample, amd2ldif, am-eject, Assorted Tools +@comment node-name, next, previous, up +@section amd.conf-sample +@pindex amd.conf-sample + +A sample @i{Amd} configuration file. @xref{Amd Configuration File}. + +@c ---------------------------------------------------------------- +@node amd2ldif, amd2sun, amd.conf-sample, Assorted Tools +@comment node-name, next, previous, up +@section amd2ldif +@pindex amd2ldif + +A script to convert @i{Amd} maps to LDAP input files. Use it as follows: + +@example +amd2ldif @i{mapname} @i{base} < @i{amd.mapfile} > @i{mapfile.ldif} +@end example + +@c ---------------------------------------------------------------- +@node amd2sun, ctl-amd, amd2ldif, Assorted Tools +@comment node-name, next, previous, up +@section amd2sun +@pindex amd2sun + +A script to convert @i{Amd} maps to Sun Automounter maps. Use it as +follows + +@example +amd2sun < @i{amd.mapfile} > @i{auto_mapfile} +@end example + +@c ---------------------------------------------------------------- +@node ctl-amd, ctl-hlfsd, amd2sun, Assorted Tools +@comment node-name, next, previous, up +@section ctl-amd +@pindex ctl-amd + +A script to start, stop, or restart @i{Amd}. Use it as follows: + +@table @t +@item ctl-amd start +Start a new @i{Amd} process. +@item ctl-amd stop +Stop the running @i{Amd}. +@item ctl-amd restart +Stop the running @i{Amd} (if any), safely wait for it to terminate, and +then start a new process --- only if the previous one died cleanly. +@end table + +@xref{Run-time Administration} for more details. + +@c ---------------------------------------------------------------- +@node ctl-hlfsd, expn, ctl-amd, Assorted Tools +@comment node-name, next, previous, up +@section ctl-hlfsd +@pindex ctl-hlfsd + +A script for controlling @i{Hlfsd}, much the same way @file{ctl-amd} +controls @i{Amd}. Use it as follows: + +@table @t +@item ctl-hlfsd start +Start a new @i{Hlfsd} process. +@item ctl-hlfsd stop +Stop the running @i{Hlfsd}. +@item ctl-hlfsd restart +Stop the running @i{Hlfsd} (if any), wait for 10 seconds for it to +terminate, and then start a new process --- only if the previous one +died cleanly. +@end table + +@xref{Hlfsd} for more details. + +@c ---------------------------------------------------------------- +@node expn, fix-amd-map, ctl-hlfsd, Assorted Tools +@comment node-name, next, previous, up +@section expn +@pindex expn + +A script to expand email addresses into their full name. It is +generally useful when using with the @file{lostaltmail} script, but is a +useful tools otherwise. + +@example +$ expn -v ezk@@cs.columbia.edu +ezk@@cs.columbia.edu -> + ezk@@shekel.mcl.cs.columbia.edu +ezk@@shekel.mcl.cs.columbia.edu -> + Erez Zadok <"| /usr/local/mh/lib/slocal -user ezk || exit 75> + Erez Zadok <\ezk> + Erez Zadok </u/zing/ezk/.mailspool/backup> +@end example + +@c ---------------------------------------------------------------- +@node fix-amd-map, fixmount, expn, Assorted Tools +@comment node-name, next, previous, up +@section fix-amd-map +@pindex fix-amd-map + +Am-utils changed some of the syntax and default values of some +variables. For example, the default value for @samp{$@{os@}} for +Solaris 2.x (aka SunOS 5.x) systems used to be @samp{sos5}, it is now +more automatically generated from @file{config.guess} and its value is +@samp{sunos5}. + +This script converts older @i{Amd} maps to new ones. Use it as follows: + +@example +fix-amd-map < @i{old.map} > @i{new.map} +@end example + +@c ---------------------------------------------------------------- +@node fixmount, fixrmtab, fix-amd-map, Assorted Tools +@comment node-name, next, previous, up +@section fixmount +@pindex fixmount + +@samp{fixmount} is a variant of @b{showmount}(8) that can delete bogus +mount entries in remote @b{mountd}(8) daemons. This is useful to +cleanup otherwise ever-accumulating ``junk''. Use it for example: + +@example +fixmount -r @i{host} +@end example + +See the online manual page for @samp{fixmount} for more details of its +usage. + +@c ---------------------------------------------------------------- +@node fixrmtab, lostaltmail, fixmount, Assorted Tools +@comment node-name, next, previous, up +@section fixrmtab +@pindex fixrmtab + +A script to invalidate @file{/etc/rmtab} entries for hosts named. Also +restart mountd for changes to take effect. Use it for example: + +@example +fixrmtab @i{host1} @i{host2} @i{...} +@end example + +@c ---------------------------------------------------------------- +@node lostaltmail, lostaltmail.conf-sample, fixrmtab, Assorted Tools +@comment node-name, next, previous, up +@section lostaltmail +@pindex lostaltmail + +A script used with @i{Hlfsd} to resend any ``lost'' mail. @i{Hlfsd} +redirects mail which cannot be written into the user's home directory to +an alternate directory. This is useful to continue delivering mail, +even if the user's file system was unavailable, full, or over quota. +But, the mail which gets delivered to the alternate directory needs to +be resent to its respective users. This is what the @samp{lostaltmail} +script does. + +Use it as follows: + +@example +lostaltmail +@end example + +This script needs a configuration file @samp{lostaltmail.conf} set up +with the right parameters to properly work. @xref{Hlfsd} for more +details. + +@c ---------------------------------------------------------------- +@node lostaltmail.conf-sample, mk-amd-map, lostaltmail, Assorted Tools +@comment node-name, next, previous, up +@section lostaltmail.conf-sample +@pindex lostaltmail.conf-sample +@cindex lostaltmail; configuration file + +This is a text file with configuration parameters needed for the +@samp{lostaltmail} script. The script includes comments explaining each +of the configuration variables. See it for more information. Also +@pxref{Hlfsd} for general information. + +@c ---------------------------------------------------------------- +@node mk-amd-map, pawd, lostaltmail.conf-sample, Assorted Tools +@comment node-name, next, previous, up +@section mk-amd-map +@pindex mk-amd-map + +This program converts a normal @i{Amd} map file into an ndbm database +with the same prefix as the named file. Use it as follows: + +@example +mk-amd-map @i{mapname} +@end example + +@c ---------------------------------------------------------------- +@node pawd, wait4amd, mk-amd-map, Assorted Tools +@comment node-name, next, previous, up +@section pawd +@pindex pawd + +@i{Pawd} is used to print the current working directory, adjusted to +reflect proper paths that can be reused to go through the automounter +for the shortest possible path. In particular, the path printed back +does not include any of @i{Amd}'s local mount points. Using them is +unsafe, because @i{Amd} may unmount managed file systems from the mount +points, and thus including them in paths may not always find the files +within. + +Without any arguments, @i{Pawd} will print the automounter adjusted +current working directory. With any number of arguments, it will print +the adjusted path of each one of the arguments. + +@c ---------------------------------------------------------------- +@node wait4amd, wait4amd2die, pawd, Assorted Tools +@comment node-name, next, previous, up +@section wait4amd +@pindex wait4amd + +A script to wait for @i{Amd} to start on a particular host before +performing an arbitrary command. The command is executed repeatedly, +with 1 second intervals in between. You may interrupt the script using +@samp{^C} (or whatever keyboard sequence your terminal's @samp{intr} function +is bound to). + +Examples: + +@table @t +@item wait4amd saturn amq -p -h saturn +When @i{Amd} is up on host @samp{saturn}, get the process ID of that +running @i{Amd}. +@item wait4amd pluto rlogin pluto +Remote login to host @samp{pluto} when @i{Amd} is up on that host. It +is generally necessary to wait for @i{Amd} to properly start and +initialize on a remote host before logging in to it, because otherwise +user home directories may not be accessible across the network. +@item wait4amd pluto +A short-hand version of the previous command, since the most useful +reason for this script is to login to a remote host. I use it very +often when testing out new versions of @i{Amd}, and need to reboot hung +hosts. +@end table + +@c ---------------------------------------------------------------- +@node wait4amd2die, wire-test, wait4amd, Assorted Tools +@comment node-name, next, previous, up +@section wait4amd2die +@pindex wait4amd2die + +This script is used internally by @samp{ctl-amd} when used to restart +@i{Amd}. It waits for @i{Amd} to terminate. If it detected that +@i{Amd} terminated cleanly, this script will return an exist status of +zero. Otherwise, it will return a non-zero exit status. + +The script tests for @i{Amd}'s existence once every 5 seconds, six +times, for a total of 30 seconds. It will return a zero exist status as +soon as it detects that @i{Amd} dies. + +@c ---------------------------------------------------------------- +@node wire-test, , wait4amd2die, Assorted Tools +@comment node-name, next, previous, up +@section wire-test +@pindex wire-test + +A simple program to test if some of the most basic networking functions +in am-util's library @file{libamu} work. It also tests the combination +of NFS protocol and version number that are supported from the current +host, to a remote one. + +For example, in this test a machine which only supports NFS Version 2 is +contacting a remote host that can support the same version, but using +both UDP and TCP. If no host name is specified, @samp{wire-test} will +try @file{localhost}. + +@example +$ wire-test moisil +Network name is "mcl-lab-net.cs.columbia.edu" +Network number is "128.59.13" +Network name is "old-net.cs.columbia.edu" +Network number is "128.59.16" +My IP address is 0x7f000001. +NFS Version and protocol tests to host "moisil"... + testing vers=2, proto="udp" -> found version 2. + testing vers=3, proto="udp" -> failed! + testing vers=2, proto="tcp" -> found version 2. + testing vers=3, proto="tcp" -> failed! +@end example + +@c ################################################################ +@node Examples, Internals, Assorted Tools, Top +@comment node-name, next, previous, up +@chapter Examples + +@menu +* User Filesystems:: +* Home Directories:: +* Architecture Sharing:: +* Wildcard Names:: +* rwho servers:: +* /vol:: +* /defaults with selectors:: +* /tftpboot in a chroot-ed environment:: + +@end menu + +@node User Filesystems, Home Directories, Examples, Examples +@comment node-name, next, previous, up +@section User Filesystems +@cindex User filesystems +@cindex Mounting user filesystems + +With more than one fileserver, the directories most frequently +cross-mounted are those containing user home directories. A common +convention used at Imperial College is to mount the user disks under +@t{/home/}@i{machine}. + +Typically, the @samp{/etc/fstab} file contained a long list of entries +such as: + +@example +@i{machine}:/home/@i{machine} /home/@i{machine} nfs ... +@end example + +for each fileserver on the network. + +There are numerous problems with this system. The mount list can become +quite large and some of the machines may be down when a system is +booted. When a new fileserver is installed, @samp{/etc/fstab} must be +updated on every machine, the mount directory created and the filesystem +mounted. + +In many environments most people use the same few workstations, but +it is convenient to go to a colleague's machine and access your own +files. When a server goes down, it can cause a process on a client +machine to hang. By minimizing the mounted filesystems to only include +those actively being used, there is less chance that a filesystem will +be mounted when a server goes down. + +The following is a short extract from a map taken from a research fileserver +at Imperial College. + +Note the entry for @samp{localhost} which is used for users such as +the operator (@samp{opr}) who have a home directory on most machine as +@samp{/home/localhost/opr}. + +@example +/defaults opts:=rw,intr,grpid,nosuid +charm host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/xd0g +# +... + +# +localhost type:=link;fs:=$@{host@} +... +# +# dylan has two user disks so have a +# top directory in which to mount them. +# +dylan type:=auto;fs:=$@{map@};pref:=$@{key@}/ +# +dylan/dk2 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \ + host==dylan;type:=ufs;dev:=/dev/dsk/2s0 +# +dylan/dk5 host!=dylan;type:=nfs;rhost:=dylan;rfs:=/home/$@{key@} \ + host==dylan;type:=ufs;dev:=/dev/dsk/5s0 +... +# +toytown host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/xy1g +... +# +zebedee host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} \ + host==$@{key@};type:=ufs;dev:=/dev/dsk/1s0 +# +# Just for access... +# +gould type:=auto;fs:=$@{map@};pref:=$@{key@}/ +gould/staff host!=gould;type:=nfs;rhost:=gould;rfs:=/home/$@{key@} +# +gummo host!=$@{key@};type:=nfs;rhost:=$@{key@};rfs:=/home/$@{key@} +... +@end example + +This map is shared by most of the machines listed so on those +systems any of the user disks is accessible via a consistent name. +@i{Amd} is started with the following command + +@example +amd /home amd.home +@end example + +Note that when mounting a remote filesystem, the @dfn{automounted} +mount point is referenced, so that the filesystem will be mounted if +it is not yet (at the time the remote @samp{mountd} obtains the file handle). + +@node Home Directories, Architecture Sharing, User Filesystems, Examples +@comment node-name, next, previous, up +@section Home Directories +@cindex Home directories +@cindex Example of mounting home directories +@cindex Mount home directories + +One convention for home directories is to locate them in @samp{/homes} +so user @samp{jsp}'s home directory is @samp{/homes/jsp}. With more +than a single fileserver it is convenient to spread user files across +several machines. All that is required is a mount-map which converts +login names to an automounted directory. + +Such a map might be started by the command: + +@example +amd /homes amd.homes +@end example + +where the map @samp{amd.homes} contained the entries: + +@example +/defaults type:=link # All the entries are of type:=link +jsp fs:=/home/charm/jsp +njw fs:=/home/dylan/dk5/njw +... +phjk fs:=/home/toytown/ai/phjk +sjv fs:=/home/ganymede/sjv +@end example + +Whenever a login name is accessed in @samp{/homes} a symbolic link +appears pointing to the real location of that user's home directory. In +this example, @samp{/homes/jsp} would appear to be a symbolic link +pointing to @samp{/home/charm/jsp}. Of course, @samp{/home} would also +be an automount point. + +This system causes an extra level of symbolic links to be used. +Although that turns out to be relatively inexpensive, an alternative is +to directly mount the required filesystems in the @samp{/homes} +map. The required map is simple, but long, and its creation is best automated. +The entry for @samp{jsp} could be: + +@example +jsp -sublink:=$@{key@};rfs:=/home/charm \ + host==charm;type:=ufs;dev:=/dev/xd0g \ + host!=charm;type:=nfs;rhost:=charm +@end example + +This map can become quite big if it contains a large number of entries. +By combining two other features of @i{Amd} it can be greatly simplified. + +First the UFS partitions should be mounted under the control of +@samp{/etc/fstab}, taking care that they are mounted in the same place +that @i{Amd} would have automounted them. In most cases this would be +something like @samp{/a/@dfn{host}/home/@dfn{host}} and +@samp{/etc/fstab} on host @samp{charm} would have a line:@refill + +@example +/dev/xy0g /a/charm/home/charm 4.2 rw,nosuid,grpid 1 5 +@end example + +The map can then be changed to: + +@example +/defaults type:=nfs;sublink:=$@{key@};opts:=rw,intr,nosuid,grpid +jsp rhost:=charm;rfs:=/home/charm +njw rhost:=dylan;rfs:=/home/dylan/dk5 +... +phjk rhost:=toytown;rfs:=/home/toytown;sublink:=ai/$@{key@} +sjv rhost:=ganymede;rfs:=/home/ganymede +@end example + +This map operates as usual on a remote machine (@i{ie} @code{$@{host@}} +not equal to @code{$@{rhost@}}). On the machine where the filesystem is +stored (@i{ie} @code{$@{host@}} equal to @code{$@{rhost@}}), @i{Amd} +will construct a local filesystem mount point which corresponds to the +name of the locally mounted UFS partition. If @i{Amd} is started with +the @code{-r} option then instead of attempting an NFS mount, @i{Amd} will +simply inherit the UFS mount (@pxref{Inheritance Filesystem}). If +@code{-r} is not used then a loopback NFS mount will be made. This type of +mount is known to cause a deadlock on many systems. + +@node Architecture Sharing, Wildcard Names, Home Directories, Examples +@comment node-name, next, previous, up +@section Architecture Sharing +@cindex Architecture sharing +@cindex Sharing a fileserver between architectures +@cindex Architecture dependent volumes + +@c %At the moment some of the research machines have sets of software +@c %mounted in @samp{/vol}. This contains subdirectories for \TeX, +@c %system sources, local sources, prolog libraries and so on. +Often a filesystem will be shared by machines of different architectures. +Separate trees can be maintained for the executable images for each +architecture, but it may be more convenient to have a shared tree, +with distinct subdirectories. + +A shared tree might have the following structure on the fileserver (called +@samp{fserver} in the example): + +@example +local/tex +local/tex/fonts +local/tex/lib +local/tex/bin +local/tex/bin/sun3 +local/tex/bin/sun4 +local/tex/bin/hp9000 +... +@end example + +In this example, the subdirectories of @samp{local/tex/bin} should be +hidden when accessed via the automount point (conventionally @samp{/vol}). +A mount-map for @samp{/vol} to achieve this would look like: + +@example +/defaults sublink:=$@{/key@};rhost:=fserver;type:=link +tex type:=auto;fs:=$@{map@};pref:=$@{key@}/ +tex/fonts host!=fserver;type:=nfs;rfs:=/vol/tex \ + host==fserver;fs:=/usr/local/tex +tex/lib host!=fserver;type:=nfs;rfs:=/vol/tex \ + host==fserver;fs:=/usr/local/tex +tex/bin -sublink:=$@{/key@}/$@{arch@} \ + host!=fserver;type:=nfs;rfs:=/vol/tex \ + host:=fserver;fs:=/usr/local/tex +@end example + +When @samp{/vol/tex/bin} is referenced, the current machine architecture +is automatically appended to the path by the @code{$@{sublink@}} +variable. This means that users can have @samp{/vol/tex/bin} in their +@samp{PATH} without concern for architecture dependencies. + +@node Wildcard Names, rwho servers, Architecture Sharing, Examples +@comment node-name, next, previous, up +@section Wildcard Names & Replicated Servers + +By using the wildcard facility, @i{Amd} can @dfn{overlay} an existing +directory with additional entries. +The system files are usually mounted under @samp{/usr}. If instead, +@i{Amd} is mounted on @samp{/usr}, additional +names can be overlayed to augment or replace names in the ``master'' @samp{/usr}. +A map to do this would have the form: + +@example +local type:=auto;fs:=local-map +share type:=auto;fs:=share-map +* -type:=nfs;rfs:=/export/exec/$@{arch@};sublink:="$@{key@}" \ + rhost:=fserv1 rhost:=fserv2 rhost:=fserv3 +@end example + +Note that the assignment to @code{$@{sublink@}} is surrounded by double +quotes to prevent the incoming key from causing the map to be +misinterpreted. This map has the effect of directing any access to +@samp{/usr/local} or @samp{/usr/share} to another automount point. + +In this example, it is assumed that the @samp{/usr} files are replicated +on three fileservers: @samp{fserv1}, @samp{fserv2} and @samp{fserv3}. +For any references other than to @samp{local} and @samp{share} one of +the servers is used and a symbolic link to +@t{$@{autodir@}/$@{rhost@}/export/exec/$@{arch@}/@i{whatever}} is +returned once an appropriate filesystem has been mounted.@refill + +@node rwho servers, /vol, Wildcard Names, Examples +@comment node-name, next, previous, up +@section @samp{rwho} servers +@cindex rwho servers +@cindex Architecture specific mounts +@cindex Example of architecture specific mounts + +The @samp{/usr/spool/rwho} directory is a good candidate for automounting. +For efficiency reasons it is best to capture the rwho data on a small +number of machines and then mount that information onto a large number +of clients. The data written into the rwho files is byte order dependent +so only servers with the correct byte ordering can be used by a client: + +@example +/defaults type:=nfs +usr/spool/rwho -byte==little;rfs:=/usr/spool/rwho \ + rhost:=vaxA rhost:=vaxB \ + || -rfs:=/usr/spool/rwho \ + rhost:=sun4 rhost:=hp300 +@end example + +@node /vol, /defaults with selectors, rwho servers, Examples +@comment node-name, next, previous, up +@section @samp{/vol} +@cindex /vol +@cindex Catch-all mount point +@cindex Generic volume name + +@samp{/vol} is used as a catch-all for volumes which do not have other +conventional names. + +Below is part of the @samp{/vol} map for the domain @samp{doc.ic.ac.uk}. +The @samp{r+d} tree is used for new or experimental software that needs +to be available everywhere without installing it on all the fileservers. +Users wishing to try out the new software then simply include +@samp{/vol/r+d/@{bin,ucb@}} in their path.@refill + +The main tree resides on one host @samp{gould.doc.ic.ac.uk}, which has +different @samp{bin}, @samp{etc}, @samp{lib} and @samp{ucb} +sub-directories for each machine architecture. For example, +@samp{/vol/r+d/bin} for a Sun-4 would be stored in the sub-directory +@samp{bin/sun4} of the filesystem @samp{/usr/r+d}. When it was accessed +a symbolic link pointing to @samp{/a/gould/usr/r+d/bin/sun4} would be +returned.@refill + +@example +/defaults type:=nfs;opts:=rw,grpid,nosuid,intr,soft +wp -opts:=rw,grpid,nosuid;rhost:=charm \ + host==charm;type:=link;fs:=/usr/local/wp \ + host!=charm;type:=nfs;rfs:=/vol/wp +... +# +src -opts:=rw,grpid,nosuid;rhost:=charm \ + host==charm;type:=link;fs:=/usr/src \ + host!=charm;type:=nfs;rfs:=/vol/src +# +r+d type:=auto;fs:=$@{map@};pref:=r+d/ +# per architecture bin,etc,lib&ucb... +r+d/bin rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/etc rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/include rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/lib rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +r+d/man rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/src rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@} +r+d/ucb rhost:=gould.doc.ic.ac.uk;rfs:=/usr/r+d;sublink:=$@{/key@}/$@{arch@} +# hades pictures +pictures -opts:=rw,grpid,nosuid;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/pictures \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=pictures +# hades tools +hades -opts:=rw,grpid,nosuid;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/hades \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=hades +# bsd tools for hp. +bsd -opts:=rw,grpid,nosuid;arch==hp9000;rhost:=thpfs \ + host==thpfs;type:=link;fs:=/nbsd/bsd \ + host!=thpfs;type:=nfs;rfs:=/nbsd;sublink:=bsd +@end example + +@node /defaults with selectors, /tftpboot in a chroot-ed environment, /vol, Examples +@comment node-name, next, previous, up +@section @samp{/defaults} with selectors +@cindex /defaults with selectors +@cindex selectors on default + +It is sometimes useful to have different defaults for a given map. To +achieve this, the @samp{/defaults} entry must be able to process normal +selectors. This feature is turned on by setting +@samp{selectors_on_default = yes} in the @file{amd.conf} file. +@xref{selectors_on_default Parameter}. + +In this example, I set different default NFS mount options for hosts +which are running over a slower network link. By setting a smaller size +for the NFS read and write buffer sizes, you can greatly improve remote +file service performance. + +@example +/defaults \ + wire==slip-net;opts:=rw,intr,rsize=1024,wsize=1024,timeo=20,retrans=10 \ + wire!=slip-net;opts:=rw,intr +@end example + +@node /tftpboot in a chroot-ed environment, , /defaults with selectors, Examples +@comment node-name, next, previous, up +@section @samp{/tftpboot} in a chroot-ed environment +@cindex /tftpboot in a chroot-ed environment +@cindex chroot: /tftpboot example + +In this complex example, we attempt to run an @i{Amd} process +@emph{inside} a chroot-ed environment. @samp{tftpd} (Trivial FTP) is +used to trivially retrieve files used to boot X-Terminals, Network +Printers, Network routers, diskless workstations, and other such +devices. For security reasons, @samp{tftpd} (and also @samp{ftpd}) +processes are run using the @b{chroot}(2) system call. This provides an +environment for these processes, where access to any files outside the +directory where the chroot-ed process runs is denied. + +For example, if you start @samp{tftpd} on your system with + +@example +chroot /tftpboot /usr/sbin/tftpd +@end example + +@noindent +then the @samp{tftpd} process will not be able to access any files +outside @file{/tftpboot}. This ensures that no one can retrieve files +such as @file{/etc/passwd} and run password crackers on it. + +Since the TFTP service works by broadcast, it is necessary to have at +least one TFTP server running on each subnet. If you have lots of files +that you need to make available for @samp{tftp}, and many subnets, it +could take significant amounts of disk space on each host serving them. + +A solution we implemented at Columbia University was to have every host +run @samp{tftpd}, but have those servers retrieve the boot files from +two replicated servers. Those replicated servers have special +partitions dedicated to the many network boot files. + +We start @i{Amd} as follows: + +@example +amd /tftpboot/.amd amd.tftpboot +@end example + +That is, @i{Amd} is serving the directory @file{/tftpboot/.amd}. The +@samp{tftp} server runs inside @file{/tftpboot} and is chroot-ed in that +directory too. The @file{amd.tftpboot} map looks like: + +@example +# +# Amd /tftpboot directory -> host map +# + +/defaults opts:=nosuid,ro,intr,soft;fs:=/tftpboot/import;type:=nfs + +tp host==lol;rfs:=/n/lol/import/tftpboot;type:=lofs \ + host==ober;rfs:=/n/ober/misc/win/tftpboot;type:=lofs \ + rhost:=ober;rfs:=/n/ober/misc/win/tftpboot \ + rhost:=lol;rfs:=/n/lol/import/tftpboot +@end example + +To help understand this example, I list a few of the file entries that +are created inside @file{/tftpboot}: + +@example +$ ls -la /tftpboot +dr-xr-xr-x 2 root 512 Aug 30 23:11 .amd +drwxrwsr-x 12 root 512 Aug 30 08:00 import +lrwxrwxrwx 1 root 33 Feb 27 1997 adminpr.cfg -> ./.amd/tp/hplj/adminpr.cfg +lrwxrwxrwx 1 root 22 Dec 5 1996 tekxp -> ./.amd/tp/xterms/tekxp +lrwxrwxrwx 1 root 1 Dec 5 1996 tftpboot -> . +@end example + +Here is an explanation of each of the entries listed above: + +@table @code + +@item .amd +This is the @i{Amd} mount point. Note that you do not need to run a +separate @i{Amd} process for the TFTP service. The @b{chroot}(2) system +call only protects against file access, but the same process can still +serve files and directories inside and outside the chroot-ed +environment, because @i{Amd} itself was not run in chroot-ed mode. + +@item import +This is the mount point where @i{Amd} will mount the directories +containing the boot files. The map is designed so that remote +directories will be NFS mounted (even if they are already mounted +elsewhere), and local directories are loopback mounted (since they are +not accessible outside the chroot-ed @file{/tftpboot} directory). + +@item adminpr.cfg +@itemx tekxp +Two manually created symbolic links to directories @emph{inside} the +@i{Amd}-managed directory. The crossing of the component @file{tp} will +cause @i{Amd} to automount one of the remote replicas. Once crossed, +access to files inside proceeds as usual. The @samp{adminpr.cfg} is a +configuration file for an HP Laser-Jet 4si printer, and the @samp{tekxp} +is a directory for Tektronix X-Terminal boot files. + +@item tftpboot +This innocent looking symlink is important. Usually, when devices boot +via the TFTP service, they perform the @samp{get file} command to +retrieve @var{file}. However, some devices assume that @samp{tftpd} +does not run in a chroot-ed environment, but rather ``unprotected'', and +thus use a full pathname for files to retrieve, as in @samp{get +/tftpboot/file}. This symlink effectively strips out the leading +@file{/tftpboot/}. + +@end table + +@c ################################################################ +@node Internals, Acknowledgments & Trademarks, Examples, Top +@comment node-name, next, previous, up +@chapter Internals + +Note that there are more error and logging messages possible than are +listed here. Most of them are self-explanatory. Refer to the program +sources for more details on the rest. + +@menu +* Log Messages:: +@end menu + +@node Log Messages, , Internals, Internals +@comment node-name, next, previous, up +@section Log Messages + +In the following sections a brief explanation is given of some of the +log messages made by @i{Amd}. Where the message is in @samp{typewriter} +font, it corresponds exactly to the message produced by @i{Amd}. Words +in @dfn{italic} are replaced by an appropriate string. Variables, +@code{$@{@i{var}@}}, indicate that the value of the appropriate variable is +output. + +Log messages are either sent directly to a file, +or logged via the @b{syslog}(3) mechanism. @xref{log_file Parameter} +In either case, entries in the file are of the form: +@example +@i{date-string} @i{hostname} @t{amd[}@i{pid}@t{]} @i{message} +@end example + +@menu +* Fatal errors:: +* Info messages:: +@end menu + +@node Fatal errors, Info messages, Log Messages, Log Messages +@comment node-name, next, previous, up +@subsection Fatal errors + +@i{Amd} attempts to deal with unusual events. Whenever it is not +possible to deal with such an error, @i{Amd} will log an appropriate +message and, if it cannot possibly continue, will either exit or abort. +These messages are selected by @samp{-x fatal} on the command line. +When @b{syslog}(3) is being used, they are logged with level +@samp{LOG_FATAL}. Even if @i{Amd} continues to operate it is likely to +remain in a precarious state and should be restarted at the earliest +opportunity. + +@table @t + +@item Attempting to inherit not-a-filesystem +The prototype mount point created during a filesystem restart did not +contain a reference to the restarted filesystem. This error ``should +never happen''. + +@item Can't bind to domain "@i{NIS-domain}" +A specific NIS domain was requested on the command line, but no server +for that domain is available on the local net. + +@item Can't determine IP address of this host (@i{hostname}) +When @i{Amd} starts it determines its own IP address. If this lookup +fails then @i{Amd} cannot continue. The hostname it looks up is that +obtained returned by @b{gethostname}(2) system call. + +@item Can't find root file handle for @i{automount point} +@i{Amd} creates its own file handles for the automount points. When it +mounts itself as a server, it must pass these file handles to the local +kernel. If the filehandle is not obtainable the mount point is ignored. +This error ``should never happen''. + +@item Must be root to mount filesystems (euid = @i{euid}) +To prevent embarrassment, @i{Amd} makes sure it has appropriate system +privileges. This amounts to having an euid of 0. The check is made +after argument processing complete to give non-root users a chance to +access the @code{-v} option. + +@item No work to do - quitting +No automount points were given on the command line and so there is no +work to do. + +@item Out of memory +While attempting to malloc some memory, the memory space available to +@i{Amd} was exhausted. This is an unrecoverable error. + +@item Out of memory in realloc +While attempting to realloc some memory, the memory space available to +@i{Amd} was exhausted. This is an unrecoverable error. + +@item cannot create rpc/udp service +Either the NFS or AMQ endpoint could not be created. + +@item gethostname: @i{description} +The @b{gethostname}(2) system call failed during startup. + +@item host name is not set +The @b{gethostname}(2) system call returned a zero length host name. +This can happen if @i{Amd} is started in single user mode just after +booting the system. + +@item ifs_match called! +An internal error occurred while restarting a pre-mounted filesystem. +This error ``should never happen''. + +@item mount_afs: @i{description} +An error occurred while @i{Amd} was mounting itself. + +@item run_rpc failed +Somehow the main NFS server loop failed. This error ``should never +happen''. + +@item unable to free rpc arguments in amqprog_1 +The incoming arguments to the AMQ server could not be free'ed. + +@item unable to free rpc arguments in nfs_program_1 +The incoming arguments to the NFS server could not be free'ed. + +@item unable to register (AMQ_PROGRAM, AMQ_VERSION, udp) +The AMQ server could not be registered with the local portmapper or the +internal RPC dispatcher. + +@item unable to register (NFS_PROGRAM, NFS_VERSION, 0) +The NFS server could not be registered with the internal RPC dispatcher. + +@end table + +XXX: This section needs to be updated + +@node Info messages, , Fatal errors, Log Messages +@comment node-name, next, previous, up +@subsection Info messages + +@i{Amd} generates information messages to record state changes. These +messages are selected by @samp{-x info} on the command line. When +@b{syslog}(3) is being used, they are logged with level @samp{LOG_INFO}. + +The messages listed below can be generated and are in a format suitable +for simple statistical analysis. @dfn{mount-info} is the string +that is displayed by @dfn{Amq} in its mount information column and +placed in the system mount table. + +@table @t + +@item "@t{$@{@i{path}@}}" forcibly timed out +An automount point has been timed out by the @i{Amq} command. + +@item "@t{$@{@i{path}@}}" has timed out +No access to the automount point has been made within the timeout +period. + +@item Filehandle denied for "$@{@i{rhost}@}:$@{@i{rfs}@}" +The mount daemon refused to return a file handle for the requested filesystem. + +@item Filehandle error for "$@{@i{rhost}@}:$@{@i{rfs}@}": @i{description} +The mount daemon gave some other error for the requested filesystem. + +@item Finishing with status @i{exit-status} +@i{Amd} is about to exit with the given exit status. + +@item Re-synchronizing cache for map @t{$@{@i{map}@}} +The named map has been modified and the internal cache is being re-synchronized. + +@item file server @t{$@{@i{rhost}@}} is down - timeout of "@t{$@{@i{path}@}}" ignored +An automount point has timed out, but the corresponding file server is +known to be down. This message is only produced once for each mount +point for which the server is down. + +@item file server @t{$@{@i{rhost}@}} type nfs is down +An NFS file server that was previously up is now down. + +@item file server @t{$@{@i{rhost}@}} type nfs is up +An NFS file server that was previously down is now up. + +@item file server @t{$@{@i{rhost}@}} type nfs starts down +A new NFS file server has been referenced and is known to be down. + +@item file server @t{$@{@i{rhost}@}} type nfs starts up +A new NFS file server has been referenced and is known to be up. + +@item mount of "@t{$@{@i{path}@}}" on @t{$@{@i{fs}@}} timed out +Attempts to mount a filesystem for the given automount point have failed +to complete within 30 seconds. + +@item @i{mount-info} mounted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}} +A new file system has been mounted. + +@item @i{mount-info} restarted fstype @t{$@{@i{type}@}} on @t{$@{@i{fs}@}} +@i{Amd} is using a pre-mounted filesystem to satisfy a mount request. + +@item @i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}} +A file system has been unmounted. + +@item @i{mount-info} unmounted fstype @t{$@{@i{type}@}} from @t{$@{@i{fs}@}} link @t{$@{@i{fs}@}}/@t{$@{@i{sublink}@}} +A file system of which only a sub-directory was in use has been unmounted. + +@item restarting @i{mount-info} on @t{$@{@i{fs}@}} +A pre-mounted file system has been noted. + +@end table + +XXX: This section needs to be updated + +@c ################################################################ +@node Acknowledgments & Trademarks, Index, Internals, Top +@comment node-name, next, previous, up +@unnumbered Acknowledgments & Trademarks + +Many thanks to the @email{amd-dev@@majordomo.cs.columbia.edu,Amd +Developers} mailing list through the months developing am-utils. These +members have contributed to the discussions, ideas, code and +documentation, and subjected their systems to alpha quality code. +Special thanks go to those +@uref{http://www.cs.columbia.edu/~ezk/am-utils/AUTHORS.txt,authors} who +have submitted patches. + +Thanks to the Formal Methods Group at Imperial College for suffering +patiently while @i{Amd} was being developed on their machines. + +Thanks to the many people who have helped with the development of +@i{Amd}, especially Piete Brooks at the Cambridge University Computing +Lab for many hours of testing, experimentation and discussion. + +Thanks to the @email{amd-workers@@majordomo.glue.umd.edu,Amd Workers} +mailing list members for many suggestions and bug reports to @i{Amd}. + +@itemize @bullet +@item +@b{DEC}, @b{VAX} and @b{Ultrix} are registered trademarks of Digital +Equipment Corporation. +@item +@b{AIX} and @b{IBM} are registered trademarks of International Business +Machines Corporation. +@item +@b{Sun}, @b{NFS} and @b{SunOS} are registered trademarks of Sun +Microsystems, Inc. +@item +@b{UNIX} is a registered trademark in the USA and other countries, +exclusively licensed through X/Open Company, Ltd. +@item +All other registered trademarks are owned by their respective owners. +@end itemize + +@c ################################################################ +@node Index, , Acknowledgments & Trademarks, Top +@comment node-name, next, previous, up +@unnumbered Index + +@printindex cp + +@contents +@bye + +@c ==================================================================== +@c ISPELL LOCAL WORDS: +@c LocalWords: setfilename amdref overfullrule settitle titlepage titlefont nz +@c LocalWords: authorfont vskip ifinfo iftex cindex unnumberedsec dfn xref vol +@c LocalWords: locationN pxref jpo nott concentrix Sjoerd sjoerd cwi Eitan vuw +@c LocalWords: Mizrotsky eitan shumuji dgux fpx scp hcx metcalf masala hlh OTS +@c LocalWords: Presnell srp cgl Trost trost ogi pyrOSx OSx tubsibr riscix iX +@c LocalWords: Piete pb Lindblad cjl ai umax utek xinu Mitchum D'Souza dsouza +@c LocalWords: mrc apu alliant aviion AViiON fps macII multimax tahoe vax emph +@c LocalWords: mapdefault valA valB valC YPTSDIR ETCDIR substr MAKEDBM YPDBDIR +@c LocalWords: NOPUSH njw dylan dk dylan njw anydir domN achilles mjh pref sel +@c LocalWords: gdef loc loc loc ldots autodir remopts rwho rwho styx styx yoyo +@c LocalWords: noindent gould rvdmount rvdunmount fserver mtmp unioned logfile +@c LocalWords: dmn esac phjk toytown toytown toytown toytown phjk RdDir RdLnk +@c LocalWords: volname attrs netif dougal inaddr hwaddr ec mountmaps passno xy +@c LocalWords: freq dumpset hfs brian florence localinfo fstabs automaps defn +@c LocalWords: localname fsck'd opr gummo sjv ganymede sjv fserv fserv fserv +@c LocalWords: vaxA vaxB wp thpfs nbsd asis ifs amqprog free'ed printindex gov +@c LocalWords: LocalWords syncodeindex Distrib bsdnet lanl AutoMounter acis ic +@c LocalWords: ac uk aix bsd Mullender nl il DG lcs hpux irix ucsf NeXT cse cl +@c LocalWords: mt FX hp ibm mips utils def def Domainname eg hostd getwd tmp +@c LocalWords: subsubsection rw grpid intr noconn nocto nodevs nosuid retrans +@c LocalWords: rsize tcp timeo nounmount utimeout DDEBUG nodaemon fd hostnames +@c LocalWords: pid Amd's pendry vangogh nfsx backoff stats nomap nostats CRIT +@c LocalWords: noinfo clustername RVD dsk dsk amq hostports osver statfs str +@c LocalWords: ou counter's amdmaps proj src tftpboot sh mv cd sbin ypcat inet +@c LocalWords: Getattr getattr localhost fhandles netmask fstype noquota addr +@c LocalWords: exportfs Dumpsets dumpsets pindex ldif fixmount fixrmtab euid +@c LocalWords: lostaltmail realloc netnumber itemx primnetnum primnetname ARG +@c LocalWords: subsnetname subsnetnum netgrp netgroup multitable Shlib dec osf +@c LocalWords: hppa pc bsdi freebsd netbsd openbsd ncr sysv rs acdirmax fsid +@c LocalWords: acdirmin acregmax acregmin actimeo dumbtimr nfsv noac noauto sd +@c LocalWords: nocache nodev noint nosub pgthresh posix rdonly suid symttl mfs +@c LocalWords: AMFS umapfs myftpdir unionfs es mapname mapfile mapfile slocal +@c LocalWords: mailspool saturn saturn notknown lol ober dr xr xr drwxrwsr cfg +@c LocalWords: lrwxrwxrwx adminpr hplj adminpr cfg tekxp xterms tekxp Dupuy tp +@c LocalWords: linkname hlfsddump dirname rmtab pluto rlogin direntry pg vr dn +@c LocalWords: maxmem hlfsdir xmailbox showmount cn amdmap amdmapName resvport +@c LocalWords: objectClass amdmapKey amdmapValue ln powerpc amdmapTimestamp ez +@c LocalWords: moisil FSinfo Libtool Unmounting sublink fileservers NullProc +@c LocalWords: gethostname mount's unmounts linkx remounts unmounting UAs SA's +@c LocalWords: mountpoint mountpoints unescaped UIDs util's overlayed uref EFS +@c LocalWords: serv maxgroups nfsl cachedir copt cfsadmin efs addopts fg +@c LocalWords: nointr diff --git a/contrib/amd/doc/stamp-vti b/contrib/amd/doc/stamp-vti new file mode 100644 index 0000000..225ecdb --- /dev/null +++ b/contrib/amd/doc/stamp-vti @@ -0,0 +1,3 @@ +@set UPDATED 22 April 1998 +@set EDITION 6.0a16 +@set VERSION 6.0a16 diff --git a/contrib/amd/doc/texinfo.tex b/contrib/amd/doc/texinfo.tex new file mode 100644 index 0000000..2ce38f9 --- /dev/null +++ b/contrib/amd/doc/texinfo.tex @@ -0,0 +1,4935 @@ +%% TeX macros to handle Texinfo files. +%% $Id: texinfo.tex,v 2.218 1997/07/26 19:12:35 karl Exp $ + +% Copyright (C) 1985, 86, 88, 90, 91, 92, 93, +% 94, 95, 96, 97 Free Software Foundation, Inc. + +%This texinfo.tex file is free software; you can redistribute it and/or +%modify it under the terms of the GNU General Public License as +%published by the Free Software Foundation; either version 2, or (at +%your option) any later version. + +%This texinfo.tex file is distributed in the hope that it will be +%useful, but WITHOUT ANY WARRANTY; without even the implied warranty +%of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%General Public License for more details. + +%You should have received a copy of the GNU General Public License +%along with this texinfo.tex file; see the file COPYING. If not, write +%to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +%Boston, MA 02111-1307, USA. + + +%In other words, you are welcome to use, share and improve this program. +%You are forbidden to forbid anyone else to use, share and improve +%what you give them. Help stamp out software-hoarding! + + +% Send bug reports to bug-texinfo@prep.ai.mit.edu. +% Please include a *precise* test case in each bug report. + + +% Make it possible to create a .fmt file just by loading this file: +% if the underlying format is not loaded, start by loading it now. +% Added by gildea November 1993. +\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi + +% This automatically updates the version number based on RCS. +\def\deftexinfoversion$#1: #2 ${\def\texinfoversion{#2}} +\deftexinfoversion$Revision: 2.218 $ +\message{Loading texinfo package [Version \texinfoversion]:} + +% If in a .fmt file, print the version number +% and turn on active characters that we couldn't do earlier because +% they might have appeared in the input file name. +\everyjob{\message{[Texinfo version \texinfoversion]}\message{} + \catcode`+=\active \catcode`\_=\active} + +% Save some parts of plain tex whose names we will redefine. + +\let\ptexb=\b +\let\ptexbullet=\bullet +\let\ptexc=\c +\let\ptexcomma=\, +\let\ptexdot=\. +\let\ptexdots=\dots +\let\ptexend=\end +\let\ptexequiv = \equiv +\let\ptexi=\i +\let\ptexlbrace=\{ +\let\ptexrbrace=\} +\let\ptexstar=\* +\let\ptext=\t + +% Be sure we're in horizontal mode when doing a tie, since we make space +% equivalent to this in @example-like environments. Otherwise, a space +% at the beginning of a line will start with \penalty -- and +% since \penalty is valid in vertical mode, we'd end up putting the +% penalty on the vertical list instead of in the new paragraph. +{\catcode`@ = 11 + % Avoid using \@M directly, because that causes trouble + % if the definition is written into an index file. + \global\let\tiepenalty = \@M + \gdef\tie{\leavevmode\penalty\tiepenalty\ } +} + + +\message{Basics,} +\chardef\other=12 + +% If this character appears in an error message or help string, it +% starts a new line in the output. +\newlinechar = `^^J + +% Set up fixed words for English. +\ifx\putwordChapter\undefined{\gdef\putwordChapter{Chapter}}\fi% +\def\putwordInfo{Info}% +\ifx\putwordSee\undefined{\gdef\putwordSee{See}}\fi% +\ifx\putwordsee\undefined{\gdef\putwordsee{see}}\fi% +\ifx\putwordfile\undefined{\gdef\putwordfile{file}}\fi% +\ifx\putwordpage\undefined{\gdef\putwordpage{page}}\fi% +\ifx\putwordsection\undefined{\gdef\putwordsection{section}}\fi% +\ifx\putwordSection\undefined{\gdef\putwordSection{Section}}\fi% +\ifx\putwordTableofContents\undefined{\gdef\putwordTableofContents{Table of Contents}}\fi% +\ifx\putwordShortContents\undefined{\gdef\putwordShortContents{Short Contents}}\fi% +\ifx\putwordAppendix\undefined{\gdef\putwordAppendix{Appendix}}\fi% + +% Ignore a token. +% +\def\gobble#1{} + +\hyphenation{ap-pen-dix} +\hyphenation{mini-buf-fer mini-buf-fers} +\hyphenation{eshell} +\hyphenation{white-space} + +% Margin to add to right of even pages, to left of odd pages. +\newdimen \bindingoffset +\newdimen \normaloffset +\newdimen\pagewidth \newdimen\pageheight + +% Sometimes it is convenient to have everything in the transcript file +% and nothing on the terminal. We don't just call \tracingall here, +% since that produces some useless output on the terminal. +% +\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}% +\def\loggingall{\tracingcommands2 \tracingstats2 + \tracingpages1 \tracingoutput1 \tracinglostchars1 + \tracingmacros2 \tracingparagraphs1 \tracingrestores1 + \showboxbreadth\maxdimen\showboxdepth\maxdimen +}% + +% For @cropmarks command. +% Do @cropmarks to get crop marks. +% +\newif\ifcropmarks +\let\cropmarks = \cropmarkstrue +% +% Dimensions to add cropmarks at corners. +% Added by P. A. MacKay, 12 Nov. 1986 +% +\newdimen\cornerlong \newdimen\cornerthick +\newdimen\topandbottommargin +\newdimen\outerhsize \newdimen\outervsize +\cornerlong=1pc\cornerthick=.3pt % These set size of cropmarks +\outerhsize=7in +%\outervsize=9.5in +% Alternative @smallbook page size is 9.25in +\outervsize=9.25in +\topandbottommargin=.75in + +% Main output routine. +\chardef\PAGE = 255 +\output = {\onepageout{\pagecontents\PAGE}} + +\newbox\headlinebox +\newbox\footlinebox + +% \onepageout takes a vbox as an argument. Note that \pagecontents +% does insertions, but you have to call it yourself. +\def\onepageout#1{% + \ifcropmarks \hoffset=0pt \else \hoffset=\normaloffset \fi + % + \ifodd\pageno \advance\hoffset by \bindingoffset + \else \advance\hoffset by -\bindingoffset\fi + % + % Do this outside of the \shipout so @code etc. will be expanded in + % the headline as they should be, not taken literally (outputting ''code). + \setbox\headlinebox = \vbox{\let\hsize=\pagewidth \makeheadline}% + \setbox\footlinebox = \vbox{\let\hsize=\pagewidth \makefootline}% + % + {% + % Have to do this stuff outside the \shipout because we want it to + % take effect in \write's, yet the group defined by the \vbox ends + % before the \shipout runs. + % + \escapechar = `\\ % use backslash in output files. + \indexdummies % don't expand commands in the output. + \normalturnoffactive % \ in index entries must not stay \, e.g., if + % the page break happens to be in the middle of an example. + \shipout\vbox{% + \ifcropmarks \vbox to \outervsize\bgroup + \hsize = \outerhsize + \line{\ewtop\hfil\ewtop}% + \nointerlineskip + \line{% + \vbox{\moveleft\cornerthick\nstop}% + \hfill + \vbox{\moveright\cornerthick\nstop}% + }% + \vskip\topandbottommargin + \line\bgroup + \hfil % center the page within the outer (page) hsize. + \ifodd\pageno\hskip\bindingoffset\fi + \vbox\bgroup + \fi + % + \unvbox\headlinebox + \pagebody{#1}% + \ifdim\ht\footlinebox > 0pt + % Only leave this space if the footline is nonempty. + % (We lessened \vsize for it in \oddfootingxxx.) + % The \baselineskip=24pt in plain's \makefootline has no effect. + \vskip 2\baselineskip + \unvbox\footlinebox + \fi + % + \ifcropmarks + \egroup % end of \vbox\bgroup + \hfil\egroup % end of (centering) \line\bgroup + \vskip\topandbottommargin plus1fill minus1fill + \boxmaxdepth = \cornerthick + \line{% + \vbox{\moveleft\cornerthick\nsbot}% + \hfill + \vbox{\moveright\cornerthick\nsbot}% + }% + \nointerlineskip + \line{\ewbot\hfil\ewbot}% + \egroup % \vbox from first cropmarks clause + \fi + }% end of \shipout\vbox + }% end of group with \turnoffactive + \advancepageno + \ifnum\outputpenalty>-20000 \else\dosupereject\fi +} + +\newinsert\margin \dimen\margin=\maxdimen + +\def\pagebody#1{\vbox to\pageheight{\boxmaxdepth=\maxdepth #1}} +{\catcode`\@ =11 +\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi +% marginal hacks, juha@viisa.uucp (Juha Takala) +\ifvoid\margin\else % marginal info is present + \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi +\dimen@=\dp#1 \unvbox#1 +\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi +\ifr@ggedbottom \kern-\dimen@ \vfil \fi} +} + +% Here are the rules for the cropmarks. Note that they are +% offset so that the space between them is truly \outerhsize or \outervsize +% (P. A. MacKay, 12 November, 1986) +% +\def\ewtop{\vrule height\cornerthick depth0pt width\cornerlong} +\def\nstop{\vbox + {\hrule height\cornerthick depth\cornerlong width\cornerthick}} +\def\ewbot{\vrule height0pt depth\cornerthick width\cornerlong} +\def\nsbot{\vbox + {\hrule height\cornerlong depth\cornerthick width\cornerthick}} + +% Parse an argument, then pass it to #1. The argument is the rest of +% the input line (except we remove a trailing comment). #1 should be a +% macro which expects an ordinary undelimited TeX argument. +% +\def\parsearg#1{% + \let\next = #1% + \begingroup + \obeylines + \futurelet\temp\parseargx +} + +% If the next token is an obeyed space (from an @example environment or +% the like), remove it and recurse. Otherwise, we're done. +\def\parseargx{% + % \obeyedspace is defined far below, after the definition of \sepspaces. + \ifx\obeyedspace\temp + \expandafter\parseargdiscardspace + \else + \expandafter\parseargline + \fi +} + +% Remove a single space (as the delimiter token to the macro call). +{\obeyspaces % + \gdef\parseargdiscardspace {\futurelet\temp\parseargx}} + +{\obeylines % + \gdef\parseargline#1^^M{% + \endgroup % End of the group started in \parsearg. + % + % First remove any @c comment, then any @comment. + % Result of each macro is put in \toks0. + \argremovec #1\c\relax % + \expandafter\argremovecomment \the\toks0 \comment\relax % + % + % Call the caller's macro, saved as \next in \parsearg. + \expandafter\next\expandafter{\the\toks0}% + }% +} + +% Since all \c{,omment} does is throw away the argument, we can let TeX +% do that for us. The \relax here is matched by the \relax in the call +% in \parseargline; it could be more or less anything, its purpose is +% just to delimit the argument to the \c. +\def\argremovec#1\c#2\relax{\toks0 = {#1}} +\def\argremovecomment#1\comment#2\relax{\toks0 = {#1}} + +% \argremovec{,omment} might leave us with trailing spaces, though; e.g., +% @end itemize @c foo +% will have two active spaces as part of the argument with the +% `itemize'. Here we remove all active spaces from #1, and assign the +% result to \toks0. +% +% This loses if there are any *other* active characters besides spaces +% in the argument -- _ ^ +, for example -- since they get expanded. +% Fortunately, Texinfo does not define any such commands. (If it ever +% does, the catcode of the characters in questionwill have to be changed +% here.) But this means we cannot call \removeactivespaces as part of +% \argremovec{,omment}, since @c uses \parsearg, and thus the argument +% that \parsearg gets might well have any character at all in it. +% +\def\removeactivespaces#1{% + \begingroup + \ignoreactivespaces + \edef\temp{#1}% + \global\toks0 = \expandafter{\temp}% + \endgroup +} + +% Change the active space to expand to nothing. +% +\begingroup + \obeyspaces + \gdef\ignoreactivespaces{\obeyspaces\let =\empty} +\endgroup + + +\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next} + +%% These are used to keep @begin/@end levels from running away +%% Call \inENV within environments (after a \begingroup) +\newif\ifENV \ENVfalse \def\inENV{\ifENV\relax\else\ENVtrue\fi} +\def\ENVcheck{% +\ifENV\errmessage{Still within an environment. Type Return to continue.} +\endgroup\fi} % This is not perfect, but it should reduce lossage + +% @begin foo is the same as @foo, for now. +\newhelp\EMsimple{Type <Return> to continue.} + +\outer\def\begin{\parsearg\beginxxx} + +\def\beginxxx #1{% +\expandafter\ifx\csname #1\endcsname\relax +{\errhelp=\EMsimple \errmessage{Undefined command @begin #1}}\else +\csname #1\endcsname\fi} + +% @end foo executes the definition of \Efoo. +% +\def\end{\parsearg\endxxx} +\def\endxxx #1{% + \removeactivespaces{#1}% + \edef\endthing{\the\toks0}% + % + \expandafter\ifx\csname E\endthing\endcsname\relax + \expandafter\ifx\csname \endthing\endcsname\relax + % There's no \foo, i.e., no ``environment'' foo. + \errhelp = \EMsimple + \errmessage{Undefined command `@end \endthing'}% + \else + \unmatchedenderror\endthing + \fi + \else + % Everything's ok; the right environment has been started. + \csname E\endthing\endcsname + \fi +} + +% There is an environment #1, but it hasn't been started. Give an error. +% +\def\unmatchedenderror#1{% + \errhelp = \EMsimple + \errmessage{This `@end #1' doesn't have a matching `@#1'}% +} + +% Define the control sequence \E#1 to give an unmatched @end error. +% +\def\defineunmatchedend#1{% + \expandafter\def\csname E#1\endcsname{\unmatchedenderror{#1}}% +} + + +% Single-spacing is done by various environments (specifically, in +% \nonfillstart and \quotations). +\newskip\singlespaceskip \singlespaceskip = 12.5pt +\def\singlespace{% + % Why was this kern here? It messes up equalizing space above and below + % environments. --karl, 6may93 + %{\advance \baselineskip by -\singlespaceskip + %\kern \baselineskip}% + \setleading \singlespaceskip +} + +%% Simple single-character @ commands + +% @@ prints an @ +% Kludge this until the fonts are right (grr). +\def\@{{\tt \char '100}} + +% This is turned off because it was never documented +% and you can use @w{...} around a quote to suppress ligatures. +%% Define @` and @' to be the same as ` and ' +%% but suppressing ligatures. +%\def\`{{`}} +%\def\'{{'}} + +% Used to generate quoted braces. +\def\mylbrace {{\tt \char '173}} +\def\myrbrace {{\tt \char '175}} +\let\{=\mylbrace +\let\}=\myrbrace +\begingroup + % Definitions to produce actual \{ & \} command in an index. + \catcode`\{ = 12 \catcode`\} = 12 + \catcode`\[ = 1 \catcode`\] = 2 + \catcode`\@ = 0 \catcode`\\ = 12 + @gdef@lbracecmd[\{]% + @gdef@rbracecmd[\}]% +@endgroup + +% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent +% Others are defined by plain TeX: @` @' @" @^ @~ @= @v @H. +\let\, = \c +\let\dotaccent = \. +\def\ringaccent#1{{\accent23 #1}} +\let\tieaccent = \t +\let\ubaraccent = \b +\let\udotaccent = \d + +% Other special characters: @questiondown @exclamdown +% Plain TeX defines: @AA @AE @O @OE @L (and lowercase versions) @ss. +\def\questiondown{?`} +\def\exclamdown{!`} + +% Dotless i and dotless j, used for accents. +\def\imacro{i} +\def\jmacro{j} +\def\dotless#1{% + \def\temp{#1}% + \ifx\temp\imacro \ptexi + \else\ifx\temp\jmacro \j + \else \errmessage{@dotless can be used only with i or j}% + \fi\fi +} + +% @: forces normal size whitespace following. +\def\:{\spacefactor=1000 } + +% @* forces a line break. +\def\*{\hfil\break\hbox{}\ignorespaces} + +% @. is an end-of-sentence period. +\def\.{.\spacefactor=3000 } + +% @enddots{} is an end-of-sentence ellipsis. +\gdef\enddots{$\mathinner{\ldotp\ldotp\ldotp\ldotp}$\spacefactor=3000} + +% @! is an end-of-sentence bang. +\gdef\!{!\spacefactor=3000 } + +% @? is an end-of-sentence query. +\gdef\?{?\spacefactor=3000 } + +% @w prevents a word break. Without the \leavevmode, @w at the +% beginning of a paragraph, when TeX is still in vertical mode, would +% produce a whole line of output instead of starting the paragraph. +\def\w#1{\leavevmode\hbox{#1}} + +% @group ... @end group forces ... to be all on one page, by enclosing +% it in a TeX vbox. We use \vtop instead of \vbox to construct the box +% to keep its height that of a normal line. According to the rules for +% \topskip (p.114 of the TeXbook), the glue inserted is +% max (\topskip - \ht (first item), 0). If that height is large, +% therefore, no glue is inserted, and the space between the headline and +% the text is small, which looks bad. +% +\def\group{\begingroup + \ifnum\catcode13=\active \else + \errhelp = \groupinvalidhelp + \errmessage{@group invalid in context where filling is enabled}% + \fi + % + % The \vtop we start below produces a box with normal height and large + % depth; thus, TeX puts \baselineskip glue before it, and (when the + % next line of text is done) \lineskip glue after it. (See p.82 of + % the TeXbook.) Thus, space below is not quite equal to space + % above. But it's pretty close. + \def\Egroup{% + \egroup % End the \vtop. + \endgroup % End the \group. + }% + % + \vtop\bgroup + % We have to put a strut on the last line in case the @group is in + % the midst of an example, rather than completely enclosing it. + % Otherwise, the interline space between the last line of the group + % and the first line afterwards is too small. But we can't put the + % strut in \Egroup, since there it would be on a line by itself. + % Hence this just inserts a strut at the beginning of each line. + \everypar = {\strut}% + % + % Since we have a strut on every line, we don't need any of TeX's + % normal interline spacing. + \offinterlineskip + % + % OK, but now we have to do something about blank + % lines in the input in @example-like environments, which normally + % just turn into \lisppar, which will insert no space now that we've + % turned off the interline space. Simplest is to make them be an + % empty paragraph. + \ifx\par\lisppar + \edef\par{\leavevmode \par}% + % + % Reset ^^M's definition to new definition of \par. + \obeylines + \fi + % + % Do @comment since we are called inside an environment such as + % @example, where each end-of-line in the input causes an + % end-of-line in the output. We don't want the end-of-line after + % the `@group' to put extra space in the output. Since @group + % should appear on a line by itself (according to the Texinfo + % manual), we don't worry about eating any user text. + \comment +} +% +% TeX puts in an \escapechar (i.e., `@') at the beginning of the help +% message, so this ends up printing `@group can only ...'. +% +\newhelp\groupinvalidhelp{% +group can only be used in environments such as @example,^^J% +where each line of input produces a line of output.} + +% @need space-in-mils +% forces a page break if there is not space-in-mils remaining. + +\newdimen\mil \mil=0.001in + +\def\need{\parsearg\needx} + +% Old definition--didn't work. +%\def\needx #1{\par % +%% This method tries to make TeX break the page naturally +%% if the depth of the box does not fit. +%{\baselineskip=0pt% +%\vtop to #1\mil{\vfil}\kern -#1\mil\penalty 10000 +%\prevdepth=-1000pt +%}} + +\def\needx#1{% + % Go into vertical mode, so we don't make a big box in the middle of a + % paragraph. + \par + % + % Don't add any leading before our big empty box, but allow a page + % break, since the best break might be right here. + \allowbreak + \nointerlineskip + \vtop to #1\mil{\vfil}% + % + % TeX does not even consider page breaks if a penalty added to the + % main vertical list is 10000 or more. But in order to see if the + % empty box we just added fits on the page, we must make it consider + % page breaks. On the other hand, we don't want to actually break the + % page after the empty box. So we use a penalty of 9999. + % + % There is an extremely small chance that TeX will actually break the + % page at this \penalty, if there are no other feasible breakpoints in + % sight. (If the user is using lots of big @group commands, which + % almost-but-not-quite fill up a page, TeX will have a hard time doing + % good page breaking, for example.) However, I could not construct an + % example where a page broke at this \penalty; if it happens in a real + % document, then we can reconsider our strategy. + \penalty9999 + % + % Back up by the size of the box, whether we did a page break or not. + \kern -#1\mil + % + % Do not allow a page break right after this kern. + \nobreak +} + +% @br forces paragraph break + +\let\br = \par + +% @dots{} output some dots + +\def\dots{$\ldots$} + +% @page forces the start of a new page + +\def\page{\par\vfill\supereject} + +% @exdent text.... +% outputs text on separate line in roman font, starting at standard page margin + +% This records the amount of indent in the innermost environment. +% That's how much \exdent should take out. +\newskip\exdentamount + +% This defn is used inside fill environments such as @defun. +\def\exdent{\parsearg\exdentyyy} +\def\exdentyyy #1{{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}} + +% This defn is used inside nofill environments such as @example. +\def\nofillexdent{\parsearg\nofillexdentyyy} +\def\nofillexdentyyy #1{{\advance \leftskip by -\exdentamount +\leftline{\hskip\leftskip{\rm#1}}}} + +% @inmargin{TEXT} puts TEXT in the margin next to the current paragraph. + +\def\inmargin#1{% +\strut\vadjust{\nobreak\kern-\strutdepth + \vtop to \strutdepth{\baselineskip\strutdepth\vss + \llap{\rightskip=\inmarginspacing \vbox{\noindent #1}}\null}}} +\newskip\inmarginspacing \inmarginspacing=1cm +\def\strutdepth{\dp\strutbox} + +%\hbox{{\rm#1}}\hfil\break}} + +% @include file insert text of that file as input. +% Allow normal characters that we make active in the argument (a file name). +\def\include{\begingroup + \catcode`\\=12 + \catcode`~=12 + \catcode`^=12 + \catcode`_=12 + \catcode`|=12 + \catcode`<=12 + \catcode`>=12 + \catcode`+=12 + \parsearg\includezzz} +% Restore active chars for included file. +\def\includezzz#1{\endgroup\begingroup + % Read the included file in a group so nested @include's work. + \def\thisfile{#1}% + \input\thisfile +\endgroup} + +\def\thisfile{} + +% @center line outputs that line, centered + +\def\center{\parsearg\centerzzz} +\def\centerzzz #1{{\advance\hsize by -\leftskip +\advance\hsize by -\rightskip +\centerline{#1}}} + +% @sp n outputs n lines of vertical space + +\def\sp{\parsearg\spxxx} +\def\spxxx #1{\vskip #1\baselineskip} + +% @comment ...line which is ignored... +% @c is the same as @comment +% @ignore ... @end ignore is another way to write a comment + +\def\comment{\catcode 64=\other \catcode 123=\other \catcode 125=\other% +\parsearg \commentxxx} + +\def\commentxxx #1{\catcode 64=0 \catcode 123=1 \catcode 125=2 } + +\let\c=\comment + +% @paragraphindent is defined for the Info formatting commands only. +\let\paragraphindent=\comment + +% Prevent errors for section commands. +% Used in @ignore and in failing conditionals. +\def\ignoresections{% +\let\chapter=\relax +\let\unnumbered=\relax +\let\top=\relax +\let\unnumberedsec=\relax +\let\unnumberedsection=\relax +\let\unnumberedsubsec=\relax +\let\unnumberedsubsection=\relax +\let\unnumberedsubsubsec=\relax +\let\unnumberedsubsubsection=\relax +\let\section=\relax +\let\subsec=\relax +\let\subsubsec=\relax +\let\subsection=\relax +\let\subsubsection=\relax +\let\appendix=\relax +\let\appendixsec=\relax +\let\appendixsection=\relax +\let\appendixsubsec=\relax +\let\appendixsubsection=\relax +\let\appendixsubsubsec=\relax +\let\appendixsubsubsection=\relax +\let\contents=\relax +\let\smallbook=\relax +\let\titlepage=\relax +} + +% Used in nested conditionals, where we have to parse the Texinfo source +% and so want to turn off most commands, in case they are used +% incorrectly. +% +\def\ignoremorecommands{% + \let\defcodeindex = \relax + \let\defcv = \relax + \let\deffn = \relax + \let\deffnx = \relax + \let\defindex = \relax + \let\defivar = \relax + \let\defmac = \relax + \let\defmethod = \relax + \let\defop = \relax + \let\defopt = \relax + \let\defspec = \relax + \let\deftp = \relax + \let\deftypefn = \relax + \let\deftypefun = \relax + \let\deftypevar = \relax + \let\deftypevr = \relax + \let\defun = \relax + \let\defvar = \relax + \let\defvr = \relax + \let\ref = \relax + \let\xref = \relax + \let\printindex = \relax + \let\pxref = \relax + \let\settitle = \relax + \let\setchapternewpage = \relax + \let\setchapterstyle = \relax + \let\everyheading = \relax + \let\evenheading = \relax + \let\oddheading = \relax + \let\everyfooting = \relax + \let\evenfooting = \relax + \let\oddfooting = \relax + \let\headings = \relax + \let\include = \relax + \let\lowersections = \relax + \let\down = \relax + \let\raisesections = \relax + \let\up = \relax + \let\set = \relax + \let\clear = \relax + \let\item = \relax +} + +% Ignore @ignore ... @end ignore. +% +\def\ignore{\doignore{ignore}} + +% Ignore @ifinfo, @ifhtml, @ifnottex, @html, @menu, and @direntry text. +% +\def\ifinfo{\doignore{ifinfo}} +\def\ifhtml{\doignore{ifhtml}} +\def\ifnottex{\doignore{ifnottex}} +\def\html{\doignore{html}} +\def\menu{\doignore{menu}} +\def\direntry{\doignore{direntry}} + +% Also ignore @macro ... @end macro. The user must run texi2dvi, +% which runs makeinfo to do macro expansion. Ignore @unmacro, too. +\def\macro{\doignore{macro}} +\let\unmacro = \comment + + +% @dircategory CATEGORY -- specify a category of the dir file +% which this file should belong to. Ignore this in TeX. +\let\dircategory = \comment + +% Ignore text until a line `@end #1'. +% +\def\doignore#1{\begingroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define a command to swallow text until we reach `@end #1'. + \long\def\doignoretext##1\end #1{\enddoignore}% + % + % Make sure that spaces turn into tokens that match what \doignoretext wants. + \catcode32 = 10 + % + % Ignore braces, too, so mismatched braces don't cause trouble. + \catcode`\{ = 9 + \catcode`\} = 9 + % + % And now expand that command. + \doignoretext +} + +% What we do to finish off ignored text. +% +\def\enddoignore{\endgroup\ignorespaces}% + +\newif\ifwarnedobs\warnedobsfalse +\def\obstexwarn{% + \ifwarnedobs\relax\else + % We need to warn folks that they may have trouble with TeX 3.0. + % This uses \immediate\write16 rather than \message to get newlines. + \immediate\write16{} + \immediate\write16{***WARNING*** for users of Unix TeX 3.0!} + \immediate\write16{This manual trips a bug in TeX version 3.0 (tex hangs).} + \immediate\write16{If you are running another version of TeX, relax.} + \immediate\write16{If you are running Unix TeX 3.0, kill this TeX process.} + \immediate\write16{ Then upgrade your TeX installation if you can.} + \immediate\write16{ (See ftp://ftp.gnu.ai.mit.edu/pub/gnu/TeX.README.)} + \immediate\write16{If you are stuck with version 3.0, run the} + \immediate\write16{ script ``tex3patch'' from the Texinfo distribution} + \immediate\write16{ to use a workaround.} + \immediate\write16{} + \global\warnedobstrue + \fi +} + +% **In TeX 3.0, setting text in \nullfont hangs tex. For a +% workaround (which requires the file ``dummy.tfm'' to be installed), +% uncomment the following line: +%%%%%\font\nullfont=dummy\let\obstexwarn=\relax + +% Ignore text, except that we keep track of conditional commands for +% purposes of nesting, up to an `@end #1' command. +% +\def\nestedignore#1{% + \obstexwarn + % We must actually expand the ignored text to look for the @end + % command, so that nested ignore constructs work. Thus, we put the + % text into a \vbox and then do nothing with the result. To minimize + % the change of memory overflow, we follow the approach outlined on + % page 401 of the TeXbook: make the current font be a dummy font. + % + \setbox0 = \vbox\bgroup + % Don't complain about control sequences we have declared \outer. + \ignoresections + % + % Define `@end #1' to end the box, which will in turn undefine the + % @end command again. + \expandafter\def\csname E#1\endcsname{\egroup\ignorespaces}% + % + % We are going to be parsing Texinfo commands. Most cause no + % trouble when they are used incorrectly, but some commands do + % complicated argument parsing or otherwise get confused, so we + % undefine them. + % + % We can't do anything about stray @-signs, unfortunately; + % they'll produce `undefined control sequence' errors. + \ignoremorecommands + % + % Set the current font to be \nullfont, a TeX primitive, and define + % all the font commands to also use \nullfont. We don't use + % dummy.tfm, as suggested in the TeXbook, because not all sites + % might have that installed. Therefore, math mode will still + % produce output, but that should be an extremely small amount of + % stuff compared to the main input. + % + \nullfont + \let\tenrm = \nullfont \let\tenit = \nullfont \let\tensl = \nullfont + \let\tenbf = \nullfont \let\tentt = \nullfont \let\smallcaps = \nullfont + \let\tensf = \nullfont + % Similarly for index fonts (mostly for their use in + % smallexample) + \let\indrm = \nullfont \let\indit = \nullfont \let\indsl = \nullfont + \let\indbf = \nullfont \let\indtt = \nullfont \let\indsc = \nullfont + \let\indsf = \nullfont + % + % Don't complain when characters are missing from the fonts. + \tracinglostchars = 0 + % + % Don't bother to do space factor calculations. + \frenchspacing + % + % Don't report underfull hboxes. + \hbadness = 10000 + % + % Do minimal line-breaking. + \pretolerance = 10000 + % + % Do not execute instructions in @tex + \def\tex{\doignore{tex}}% +} + +% @set VAR sets the variable VAR to an empty value. +% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE. +% +% Since we want to separate VAR from REST-OF-LINE (which might be +% empty), we can't just use \parsearg; we have to insert a space of our +% own to delimit the rest of the line, and then take it out again if we +% didn't need it. Make sure the catcode of space is correct to avoid +% losing inside @example, for instance. +% +\def\set{\begingroup\catcode` =10 + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \parsearg\setxxx} +\def\setxxx#1{\setyyy#1 \endsetyyy} +\def\setyyy#1 #2\endsetyyy{% + \def\temp{#2}% + \ifx\temp\empty \global\expandafter\let\csname SET#1\endcsname = \empty + \else \setzzz{#1}#2\endsetzzz % Remove the trailing space \setxxx inserted. + \fi + \endgroup +} +% Can't use \xdef to pre-expand #2 and save some time, since \temp or +% \next or other control sequences that we've defined might get us into +% an infinite loop. Consider `@set foo @cite{bar}'. +\def\setzzz#1#2 \endsetzzz{\expandafter\gdef\csname SET#1\endcsname{#2}} + +% @clear VAR clears (i.e., unsets) the variable VAR. +% +\def\clear{\parsearg\clearxxx} +\def\clearxxx#1{\global\expandafter\let\csname SET#1\endcsname=\relax} + +% @value{foo} gets the text saved in variable foo. +% +\def\value{\begingroup + \catcode`\-=12 \catcode`\_=12 % Allow - and _ in VAR. + \valuexxx} +\def\valuexxx#1{% + \expandafter\ifx\csname SET#1\endcsname\relax + {\{No value for ``#1''\}}% + \else + \csname SET#1\endcsname + \fi +\endgroup} + +% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined +% with @set. +% +\def\ifset{\parsearg\ifsetxxx} +\def\ifsetxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifsetfail + \else + \expandafter\ifsetsucceed + \fi +} +\def\ifsetsucceed{\conditionalsucceed{ifset}} +\def\ifsetfail{\nestedignore{ifset}} +\defineunmatchedend{ifset} + +% @ifclear VAR ... @end ifclear reads the `...' iff VAR has never been +% defined with @set, or has been undefined with @clear. +% +\def\ifclear{\parsearg\ifclearxxx} +\def\ifclearxxx #1{% + \expandafter\ifx\csname SET#1\endcsname\relax + \expandafter\ifclearsucceed + \else + \expandafter\ifclearfail + \fi +} +\def\ifclearsucceed{\conditionalsucceed{ifclear}} +\def\ifclearfail{\nestedignore{ifclear}} +\defineunmatchedend{ifclear} + +% @iftex, @ifnothtml, @ifnotinfo always succeed; we read the text +% following, through the first @end iftex (etc.). Make `@end iftex' +% (etc.) valid only after an @iftex. +% +\def\iftex{\conditionalsucceed{iftex}} +\def\ifnothtml{\conditionalsucceed{ifnothtml}} +\def\ifnotinfo{\conditionalsucceed{ifnotinfo}} +\defineunmatchedend{iftex} +\defineunmatchedend{ifnothtml} +\defineunmatchedend{ifnotinfo} + +% We can't just want to start a group at @iftex (for example) and end it +% at @end iftex, since then @set commands inside the conditional have no +% effect (they'd get reverted at the end of the group). So we must +% define \Eiftex to redefine itself to be its previous value. (We can't +% just define it to fail again with an ``unmatched end'' error, since +% the @ifset might be nested.) +% +\def\conditionalsucceed#1{% + \edef\temp{% + % Remember the current value of \E#1. + \let\nece{prevE#1} = \nece{E#1}% + % + % At the `@end #1', redefine \E#1 to be its previous value. + \def\nece{E#1}{\let\nece{E#1} = \nece{prevE#1}}% + }% + \temp +} + +% We need to expand lots of \csname's, but we don't want to expand the +% control sequences after we've constructed them. +% +\def\nece#1{\expandafter\noexpand\csname#1\endcsname} + +% @asis just yields its argument. Used with @table, for example. +% +\def\asis#1{#1} + +% @math means output in math mode. +% We don't use $'s directly in the definition of \math because control +% sequences like \math are expanded when the toc file is written. Then, +% we read the toc file back, the $'s will be normal characters (as they +% should be, according to the definition of Texinfo). So we must use a +% control sequence to switch into and out of math mode. +% +% This isn't quite enough for @math to work properly in indices, but it +% seems unlikely it will ever be needed there. +% +\let\implicitmath = $ +\def\math#1{\implicitmath #1\implicitmath} + +% @bullet and @minus need the same treatment as @math, just above. +\def\bullet{\implicitmath\ptexbullet\implicitmath} +\def\minus{\implicitmath-\implicitmath} + +\def\node{\ENVcheck\parsearg\nodezzz} +\def\nodezzz#1{\nodexxx [#1,]} +\def\nodexxx[#1,#2]{\gdef\lastnode{#1}} +\let\nwnode=\node +\let\lastnode=\relax + +\def\donoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\setref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\unnumbnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\unnumbsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +\def\appendixnoderef{\ifx\lastnode\relax\else +\expandafter\expandafter\expandafter\appendixsetref{\lastnode}\fi +\global\let\lastnode=\relax} + +% @refill is a no-op. +\let\refill=\relax + +% @setfilename is done at the beginning of every texinfo file. +% So open here the files we need to have open while reading the input. +% This makes it possible to make a .fmt file for texinfo. +\def\setfilename{% + \readauxfile + \opencontents + \openindices + \fixbackslash % Turn off hack to swallow `\input texinfo'. + \global\let\setfilename=\comment % Ignore extra @setfilename cmds. + % + % If texinfo.cnf is present on the system, read it. + % Useful for site-wide @afourpaper, etc. + % Just to be on the safe side, close the input stream before the \input. + \openin 1 texinfo.cnf + \ifeof1 \let\temp=\relax \else \def\temp{\input texinfo.cnf }\fi + \closein1 + \temp + % + \comment % Ignore the actual filename. +} + +% @bye. +\outer\def\bye{\pagealignmacro\tracingstats=1\ptexend} + +% \def\macro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\macroxxx} +% \def\macroxxx#1#2 \end macro{% +% \expandafter\gdef\macrotemp#1{#2}% +% \endgroup} + +%\def\linemacro#1{\begingroup\ignoresections\catcode`\#=6\def\macrotemp{#1}\parsearg\linemacroxxx} +%\def\linemacroxxx#1#2 \end linemacro{% +%\let\parsearg=\relax +%\edef\macrotempx{\csname M\butfirst\expandafter\string\macrotemp\endcsname}% +%\expandafter\xdef\macrotemp{\parsearg\macrotempx}% +%\expandafter\gdef\macrotempx#1{#2}% +%\endgroup} + +%\def\butfirst#1{} + + +\message{fonts,} + +% Font-change commands. + +% Texinfo supports the sans serif font style, which plain TeX does not. +% So we set up a \sf analogous to plain's \rm, etc. +\newfam\sffam +\def\sf{\fam=\sffam \tensf} +\let\li = \sf % Sometimes we call it \li, not \sf. + +% We don't need math for this one. +\def\ttsl{\tenttsl} + +% Use Computer Modern fonts at \magstephalf (11pt). +\newcount\mainmagstep +\mainmagstep=\magstephalf + +% Set the font macro #1 to the font named #2, adding on the +% specified font prefix (normally `cm'). +% #3 is the font's design size, #4 is a scale factor +\def\setfont#1#2#3#4{\font#1=\fontprefix#2#3 scaled #4} + +% Use cm as the default font prefix. +% To specify the font prefix, you must define \fontprefix +% before you read in texinfo.tex. +\ifx\fontprefix\undefined +\def\fontprefix{cm} +\fi +% Support font families that don't use the same naming scheme as CM. +\def\rmshape{r} +\def\rmbshape{bx} %where the normal face is bold +\def\bfshape{b} +\def\bxshape{bx} +\def\ttshape{tt} +\def\ttbshape{tt} +\def\ttslshape{sltt} +\def\itshape{ti} +\def\itbshape{bxti} +\def\slshape{sl} +\def\slbshape{bxsl} +\def\sfshape{ss} +\def\sfbshape{ss} +\def\scshape{csc} +\def\scbshape{csc} + +\ifx\bigger\relax +\let\mainmagstep=\magstep1 +\setfont\textrm\rmshape{12}{1000} +\setfont\texttt\ttshape{12}{1000} +\else +\setfont\textrm\rmshape{10}{\mainmagstep} +\setfont\texttt\ttshape{10}{\mainmagstep} +\fi +% Instead of cmb10, you many want to use cmbx10. +% cmbx10 is a prettier font on its own, but cmb10 +% looks better when embedded in a line with cmr10. +\setfont\textbf\bfshape{10}{\mainmagstep} +\setfont\textit\itshape{10}{\mainmagstep} +\setfont\textsl\slshape{10}{\mainmagstep} +\setfont\textsf\sfshape{10}{\mainmagstep} +\setfont\textsc\scshape{10}{\mainmagstep} +\setfont\textttsl\ttslshape{10}{\mainmagstep} +\font\texti=cmmi10 scaled \mainmagstep +\font\textsy=cmsy10 scaled \mainmagstep + +% A few fonts for @defun, etc. +\setfont\defbf\bxshape{10}{\magstep1} %was 1314 +\setfont\deftt\ttshape{10}{\magstep1} +\def\df{\let\tentt=\deftt \let\tenbf = \defbf \bf} + +% Fonts for indices and small examples (9pt). +% We actually use the slanted font rather than the italic, +% because texinfo normally uses the slanted fonts for that. +% Do not make many font distinctions in general in the index, since they +% aren't very useful. +\setfont\ninett\ttshape{9}{1000} +\setfont\indrm\rmshape{9}{1000} +\setfont\indit\slshape{9}{1000} +\let\indsl=\indit +\let\indtt=\ninett +\let\indttsl=\ninett +\let\indsf=\indrm +\let\indbf=\indrm +\setfont\indsc\scshape{10}{900} +\font\indi=cmmi9 +\font\indsy=cmsy9 + +% Fonts for title page: +\setfont\titlerm\rmbshape{12}{\magstep3} +\setfont\titleit\itbshape{10}{\magstep4} +\setfont\titlesl\slbshape{10}{\magstep4} +\setfont\titlett\ttbshape{12}{\magstep3} +\setfont\titlettsl\ttslshape{10}{\magstep4} +\setfont\titlesf\sfbshape{17}{\magstep1} +\let\titlebf=\titlerm +\setfont\titlesc\scbshape{10}{\magstep4} +\font\titlei=cmmi12 scaled \magstep3 +\font\titlesy=cmsy10 scaled \magstep4 +\def\authorrm{\secrm} + +% Chapter (and unnumbered) fonts (17.28pt). +\setfont\chaprm\rmbshape{12}{\magstep2} +\setfont\chapit\itbshape{10}{\magstep3} +\setfont\chapsl\slbshape{10}{\magstep3} +\setfont\chaptt\ttbshape{12}{\magstep2} +\setfont\chapttsl\ttslshape{10}{\magstep3} +\setfont\chapsf\sfbshape{17}{1000} +\let\chapbf=\chaprm +\setfont\chapsc\scbshape{10}{\magstep3} +\font\chapi=cmmi12 scaled \magstep2 +\font\chapsy=cmsy10 scaled \magstep3 + +% Section fonts (14.4pt). +\setfont\secrm\rmbshape{12}{\magstep1} +\setfont\secit\itbshape{10}{\magstep2} +\setfont\secsl\slbshape{10}{\magstep2} +\setfont\sectt\ttbshape{12}{\magstep1} +\setfont\secttsl\ttslshape{10}{\magstep2} +\setfont\secsf\sfbshape{12}{\magstep1} +\let\secbf\secrm +\setfont\secsc\scbshape{10}{\magstep2} +\font\seci=cmmi12 scaled \magstep1 +\font\secsy=cmsy10 scaled \magstep2 + +% \setfont\ssecrm\bxshape{10}{\magstep1} % This size an font looked bad. +% \setfont\ssecit\itshape{10}{\magstep1} % The letters were too crowded. +% \setfont\ssecsl\slshape{10}{\magstep1} +% \setfont\ssectt\ttshape{10}{\magstep1} +% \setfont\ssecsf\sfshape{10}{\magstep1} + +%\setfont\ssecrm\bfshape{10}{1315} % Note the use of cmb rather than cmbx. +%\setfont\ssecit\itshape{10}{1315} % Also, the size is a little larger than +%\setfont\ssecsl\slshape{10}{1315} % being scaled magstep1. +%\setfont\ssectt\ttshape{10}{1315} +%\setfont\ssecsf\sfshape{10}{1315} + +%\let\ssecbf=\ssecrm + +% Subsection fonts (13.15pt). +\setfont\ssecrm\rmbshape{12}{\magstephalf} +\setfont\ssecit\itbshape{10}{1315} +\setfont\ssecsl\slbshape{10}{1315} +\setfont\ssectt\ttbshape{12}{\magstephalf} +\setfont\ssecttsl\ttslshape{10}{1315} +\setfont\ssecsf\sfbshape{12}{\magstephalf} +\let\ssecbf\ssecrm +\setfont\ssecsc\scbshape{10}{\magstep1} +\font\sseci=cmmi12 scaled \magstephalf +\font\ssecsy=cmsy10 scaled 1315 +% The smallcaps and symbol fonts should actually be scaled \magstep1.5, +% but that is not a standard magnification. + +% In order for the font changes to affect most math symbols and letters, +% we have to define the \textfont of the standard families. Since +% texinfo doesn't allow for producing subscripts and superscripts, we +% don't bother to reset \scriptfont and \scriptscriptfont (which would +% also require loading a lot more fonts). +% +\def\resetmathfonts{% + \textfont0 = \tenrm \textfont1 = \teni \textfont2 = \tensy + \textfont\itfam = \tenit \textfont\slfam = \tensl \textfont\bffam = \tenbf + \textfont\ttfam = \tentt \textfont\sffam = \tensf +} + + +% The font-changing commands redefine the meanings of \tenSTYLE, instead +% of just \STYLE. We do this so that font changes will continue to work +% in math mode, where it is the current \fam that is relevant in most +% cases, not the current font. Plain TeX does \def\bf{\fam=\bffam +% \tenbf}, for example. By redefining \tenbf, we obviate the need to +% redefine \bf itself. +\def\textfonts{% + \let\tenrm=\textrm \let\tenit=\textit \let\tensl=\textsl + \let\tenbf=\textbf \let\tentt=\texttt \let\smallcaps=\textsc + \let\tensf=\textsf \let\teni=\texti \let\tensy=\textsy \let\tenttsl=\textttsl + \resetmathfonts} +\def\titlefonts{% + \let\tenrm=\titlerm \let\tenit=\titleit \let\tensl=\titlesl + \let\tenbf=\titlebf \let\tentt=\titlett \let\smallcaps=\titlesc + \let\tensf=\titlesf \let\teni=\titlei \let\tensy=\titlesy + \let\tenttsl=\titlettsl + \resetmathfonts \setleading{25pt}} +\def\titlefont#1{{\titlefonts #1}} +\def\chapfonts{% + \let\tenrm=\chaprm \let\tenit=\chapit \let\tensl=\chapsl + \let\tenbf=\chapbf \let\tentt=\chaptt \let\smallcaps=\chapsc + \let\tensf=\chapsf \let\teni=\chapi \let\tensy=\chapsy \let\tenttsl=\chapttsl + \resetmathfonts \setleading{19pt}} +\def\secfonts{% + \let\tenrm=\secrm \let\tenit=\secit \let\tensl=\secsl + \let\tenbf=\secbf \let\tentt=\sectt \let\smallcaps=\secsc + \let\tensf=\secsf \let\teni=\seci \let\tensy=\secsy \let\tenttsl=\secttsl + \resetmathfonts \setleading{16pt}} +\def\subsecfonts{% + \let\tenrm=\ssecrm \let\tenit=\ssecit \let\tensl=\ssecsl + \let\tenbf=\ssecbf \let\tentt=\ssectt \let\smallcaps=\ssecsc + \let\tensf=\ssecsf \let\teni=\sseci \let\tensy=\ssecsy \let\tenttsl=\ssecttsl + \resetmathfonts \setleading{15pt}} +\let\subsubsecfonts = \subsecfonts % Maybe make sssec fonts scaled magstephalf? +\def\indexfonts{% + \let\tenrm=\indrm \let\tenit=\indit \let\tensl=\indsl + \let\tenbf=\indbf \let\tentt=\indtt \let\smallcaps=\indsc + \let\tensf=\indsf \let\teni=\indi \let\tensy=\indsy \let\tenttsl=\indttsl + \resetmathfonts \setleading{12pt}} + +% Set up the default fonts, so we can use them for creating boxes. +% +\textfonts + +% Count depth in font-changes, for error checks +\newcount\fontdepth \fontdepth=0 + +% Fonts for short table of contents. +\setfont\shortcontrm\rmshape{12}{1000} +\setfont\shortcontbf\bxshape{12}{1000} +\setfont\shortcontsl\slshape{12}{1000} + +%% Add scribe-like font environments, plus @l for inline lisp (usually sans +%% serif) and @ii for TeX italic + +% \smartitalic{ARG} outputs arg in italics, followed by an italic correction +% unless the following character is such as not to need one. +\def\smartitalicx{\ifx\next,\else\ifx\next-\else\ifx\next.\else\/\fi\fi\fi} +\def\smartitalic#1{{\sl #1}\futurelet\next\smartitalicx} + +\let\i=\smartitalic +\let\var=\smartitalic +\let\dfn=\smartitalic +\let\emph=\smartitalic +\let\cite=\smartitalic + +\def\b#1{{\bf #1}} +\let\strong=\b + +% We can't just use \exhyphenpenalty, because that only has effect at +% the end of a paragraph. Restore normal hyphenation at the end of the +% group within which \nohyphenation is presumably called. +% +\def\nohyphenation{\hyphenchar\font = -1 \aftergroup\restorehyphenation} +\def\restorehyphenation{\hyphenchar\font = `- } + +\def\t#1{% + {\tt \rawbackslash \frenchspacing #1}% + \null +} +\let\ttfont=\t +\def\samp #1{`\tclose{#1}'\null} +\setfont\smallrm\rmshape{8}{1000} +\font\smallsy=cmsy9 +\def\key#1{{\smallrm\textfont2=\smallsy \leavevmode\hbox{% + \raise0.4pt\hbox{$\langle$}\kern-.08em\vtop{% + \vbox{\hrule\kern-0.4pt + \hbox{\raise0.4pt\hbox{\vphantom{$\langle$}}#1}}% + \kern-0.4pt\hrule}% + \kern-.06em\raise0.4pt\hbox{$\rangle$}}}} +% The old definition, with no lozenge: +%\def\key #1{{\ttsl \nohyphenation \uppercase{#1}}\null} +\def\ctrl #1{{\tt \rawbackslash \hat}#1} + +\let\file=\samp + +% @code is a modification of @t, +% which makes spaces the same size as normal in the surrounding text. +\def\tclose#1{% + {% + % Change normal interword space to be same as for the current font. + \spaceskip = \fontdimen2\font + % + % Switch to typewriter. + \tt + % + % But `\ ' produces the large typewriter interword space. + \def\ {{\spaceskip = 0pt{} }}% + % + % Turn off hyphenation. + \nohyphenation + % + \rawbackslash + \frenchspacing + #1% + }% + \null +} + +% We *must* turn on hyphenation at `-' and `_' in \code. +% Otherwise, it is too hard to avoid overfull hboxes +% in the Emacs manual, the Library manual, etc. + +% Unfortunately, TeX uses one parameter (\hyphenchar) to control +% both hyphenation at - and hyphenation within words. +% We must therefore turn them both off (\tclose does that) +% and arrange explicitly to hyphenate at a dash. +% -- rms. +{ +\catcode`\-=\active +\catcode`\_=\active +\catcode`\|=\active +\global\def\code{\begingroup \catcode`\-=\active \let-\codedash \catcode`\_=\active \let_\codeunder \codex} +% The following is used by \doprintindex to insure that long function names +% wrap around. It is necessary for - and _ to be active before the index is +% read from the file, as \entry parses the arguments long before \code is +% ever called. -- mycroft +% _ is always active; and it shouldn't be \let = to an _ that is a +% subscript character anyway. Then, @cindex @samp{_} (for example) +% fails. --karl +\global\def\indexbreaks{% + \catcode`\-=\active \let-\realdash +} +} + +\def\realdash{-} +\def\codedash{-\discretionary{}{}{}} +\def\codeunder{\ifusingtt{\normalunderscore\discretionary{}{}{}}{\_}} +\def\codex #1{\tclose{#1}\endgroup} + +%\let\exp=\tclose %Was temporary + +% @kbd is like @code, except that if the argument is just one @key command, +% then @kbd has no effect. + +% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always), +% `example' (@kbd uses ttsl only inside of @example and friends), +% or `code' (@kbd uses normal tty font always). +\def\kbdinputstyle{\parsearg\kbdinputstylexxx} +\def\kbdinputstylexxx#1{% + \def\arg{#1}% + \ifx\arg\worddistinct + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}% + \else\ifx\arg\wordexample + \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}% + \else\ifx\arg\wordcode + \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}% + \fi\fi\fi +} +\def\worddistinct{distinct} +\def\wordexample{example} +\def\wordcode{code} + +% Default is kbdinputdistinct. (Too much of a hassle to call the macro, +% the catcodes are wrong for parsearg to work.) +\gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl} + +\def\xkey{\key} +\def\kbdfoo#1#2#3\par{\def\one{#1}\def\three{#3}\def\threex{??}% +\ifx\one\xkey\ifx\threex\three \key{#2}% +\else{\tclose{\kbdfont\look}}\fi +\else{\tclose{\kbdfont\look}}\fi} + +% @url. Quotes do not seem necessary, so use \code. +\let\url=\code + +% @uref (abbreviation for `urlref') takes an optional second argument +% specifying the text to display. First (mandatory) arg is the url. +% Perhaps eventually put in a hypertex \special here. +% +\def\uref#1{\urefxxx #1,,\finish} +\def\urefxxx#1,#2,#3\finish{% + \setbox0 = \hbox{\ignorespaces #2}% + \ifdim\wd0 > 0pt + \unhbox0\ (\code{#1})% + \else + \code{#1}% + \fi +} + +% rms does not like the angle brackets --karl, 17may97. +% So now @email is just like @uref. +%\def\email#1{$\langle${\tt #1}$\rangle$} +\let\email=\uref + +% Check if we are currently using a typewriter font. Since all the +% Computer Modern typewriter fonts have zero interword stretch (and +% shrink), and it is reasonable to expect all typewriter fonts to have +% this property, we can check that font parameter. +% +\def\ifmonospace{\ifdim\fontdimen3\font=0pt } + +% Typeset a dimension, e.g., `in' or `pt'. The only reason for the +% argument is to make the input look right: @dmn{pt} instead of +% @dmn{}pt. +% +\def\dmn#1{\thinspace #1} + +\def\kbd#1{\def\look{#1}\expandafter\kbdfoo\look??\par} + +% @l was never documented to mean ``switch to the Lisp font'', +% and it is not used as such in any manual I can find. We need it for +% Polish suppressed-l. --karl, 22sep96. +%\def\l#1{{\li #1}\null} + +\def\r#1{{\rm #1}} % roman font +% Use of \lowercase was suggested. +\def\sc#1{{\smallcaps#1}} % smallcaps font +\def\ii#1{{\it #1}} % italic font + +% @pounds{} is a sterling sign. +\def\pounds{{\it\$}} + + +\message{page headings,} + +\newskip\titlepagetopglue \titlepagetopglue = 1.5in +\newskip\titlepagebottomglue \titlepagebottomglue = 2pc + +% First the title page. Must do @settitle before @titlepage. +\newif\ifseenauthor +\newif\iffinishedtitlepage + +\def\shorttitlepage{\parsearg\shorttitlepagezzz} +\def\shorttitlepagezzz #1{\begingroup\hbox{}\vskip 1.5in \chaprm \centerline{#1}% + \endgroup\page\hbox{}\page} + +\def\titlepage{\begingroup \parindent=0pt \textfonts + \let\subtitlerm=\tenrm +% I deinstalled the following change because \cmr12 is undefined. +% This change was not in the ChangeLog anyway. --rms. +% \let\subtitlerm=\cmr12 + \def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}% + % + \def\authorfont{\authorrm \normalbaselineskip = 16pt \normalbaselines}% + % + % Leave some space at the very top of the page. + \vglue\titlepagetopglue + % + % Now you can print the title using @title. + \def\title{\parsearg\titlezzz}% + \def\titlezzz##1{\leftline{\titlefonts\rm ##1} + % print a rule at the page bottom also. + \finishedtitlepagefalse + \vskip4pt \hrule height 4pt width \hsize \vskip4pt}% + % No rule at page bottom unless we print one at the top with @title. + \finishedtitlepagetrue + % + % Now you can put text using @subtitle. + \def\subtitle{\parsearg\subtitlezzz}% + \def\subtitlezzz##1{{\subtitlefont \rightline{##1}}}% + % + % @author should come last, but may come many times. + \def\author{\parsearg\authorzzz}% + \def\authorzzz##1{\ifseenauthor\else\vskip 0pt plus 1filll\seenauthortrue\fi + {\authorfont \leftline{##1}}}% + % + % Most title ``pages'' are actually two pages long, with space + % at the top of the second. We don't want the ragged left on the second. + \let\oldpage = \page + \def\page{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + \oldpage + \let\page = \oldpage + \hbox{}}% +% \def\page{\oldpage \hbox{}} +} + +\def\Etitlepage{% + \iffinishedtitlepage\else + \finishtitlepage + \fi + % It is important to do the page break before ending the group, + % because the headline and footline are only empty inside the group. + % If we use the new definition of \page, we always get a blank page + % after the title page, which we certainly don't want. + \oldpage + \endgroup + \HEADINGSon +} + +\def\finishtitlepage{% + \vskip4pt \hrule height 2pt width \hsize + \vskip\titlepagebottomglue + \finishedtitlepagetrue +} + +%%% Set up page headings and footings. + +\let\thispage=\folio + +\newtoks \evenheadline % Token sequence for heading line of even pages +\newtoks \oddheadline % Token sequence for heading line of odd pages +\newtoks \evenfootline % Token sequence for footing line of even pages +\newtoks \oddfootline % Token sequence for footing line of odd pages + +% Now make Tex use those variables +\headline={{\textfonts\rm \ifodd\pageno \the\oddheadline + \else \the\evenheadline \fi}} +\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline + \else \the\evenfootline \fi}\HEADINGShook} +\let\HEADINGShook=\relax + +% Commands to set those variables. +% For example, this is what @headings on does +% @evenheading @thistitle|@thispage|@thischapter +% @oddheading @thischapter|@thispage|@thistitle +% @evenfooting @thisfile|| +% @oddfooting ||@thisfile + +\def\evenheading{\parsearg\evenheadingxxx} +\def\oddheading{\parsearg\oddheadingxxx} +\def\everyheading{\parsearg\everyheadingxxx} + +\def\evenfooting{\parsearg\evenfootingxxx} +\def\oddfooting{\parsearg\oddfootingxxx} +\def\everyfooting{\parsearg\everyfootingxxx} + +{\catcode`\@=0 % + +\gdef\evenheadingxxx #1{\evenheadingyyy #1@|@|@|@|\finish} +\gdef\evenheadingyyy #1@|#2@|#3@|#4\finish{% +\global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddheadingxxx #1{\oddheadingyyy #1@|@|@|@|\finish} +\gdef\oddheadingyyy #1@|#2@|#3@|#4\finish{% +\global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\everyheadingxxx#1{\oddheadingxxx{#1}\evenheadingxxx{#1}}% + +\gdef\evenfootingxxx #1{\evenfootingyyy #1@|@|@|@|\finish} +\gdef\evenfootingyyy #1@|#2@|#3@|#4\finish{% +\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}} + +\gdef\oddfootingxxx #1{\oddfootingyyy #1@|@|@|@|\finish} +\gdef\oddfootingyyy #1@|#2@|#3@|#4\finish{% + \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}% + % + % Leave some space for the footline. Hopefully ok to assume + % @evenfooting will not be used by itself. + \global\advance\pageheight by -\baselineskip + \global\advance\vsize by -\baselineskip +} + +\gdef\everyfootingxxx#1{\oddfootingxxx{#1}\evenfootingxxx{#1}} +% +}% unbind the catcode of @. + +% @headings double turns headings on for double-sided printing. +% @headings single turns headings on for single-sided printing. +% @headings off turns them off. +% @headings on same as @headings double, retained for compatibility. +% @headings after turns on double-sided headings after this page. +% @headings doubleafter turns on double-sided headings after this page. +% @headings singleafter turns on single-sided headings after this page. +% By default, they are off at the start of a document, +% and turned `on' after @end titlepage. + +\def\headings #1 {\csname HEADINGS#1\endcsname} + +\def\HEADINGSoff{ +\global\evenheadline={\hfil} \global\evenfootline={\hfil} +\global\oddheadline={\hfil} \global\oddfootline={\hfil}} +\HEADINGSoff +% When we turn headings on, set the page number to 1. +% For double-sided printing, put current file name in lower left corner, +% chapter name on inside top of right hand pages, document +% title on inside top of left hand pages, and page numbers on outside top +% edge of all pages. +\def\HEADINGSdouble{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} +\let\contentsalignmacro = \chappager + +% For single-sided printing, chapter title goes across top left of page, +% page number on top right. +\def\HEADINGSsingle{ +\global\pageno=1 +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} +\def\HEADINGSon{\HEADINGSdouble} + +\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex} +\let\HEADINGSdoubleafter=\HEADINGSafter +\def\HEADINGSdoublex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\folio\hfil\thistitle}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chapoddpage +} + +\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex} +\def\HEADINGSsinglex{% +\global\evenfootline={\hfil} +\global\oddfootline={\hfil} +\global\evenheadline={\line{\thischapter\hfil\folio}} +\global\oddheadline={\line{\thischapter\hfil\folio}} +\global\let\contentsalignmacro = \chappager +} + +% Subroutines used in generating headings +% Produces Day Month Year style of output. +\def\today{\number\day\space +\ifcase\month\or +January\or February\or March\or April\or May\or June\or +July\or August\or September\or October\or November\or December\fi +\space\number\year} + +% Use this if you want the Month Day, Year style of output. +%\def\today{\ifcase\month\or +%January\or February\or March\or April\or May\or June\or +%July\or August\or September\or October\or November\or December\fi +%\space\number\day, \number\year} + +% @settitle line... specifies the title of the document, for headings +% It generates no output of its own + +\def\thistitle{No Title} +\def\settitle{\parsearg\settitlezzz} +\def\settitlezzz #1{\gdef\thistitle{#1}} + + +\message{tables,} + +% @tabs -- simple alignment + +% These don't work. For one thing, \+ is defined as outer. +% So these macros cannot even be defined. + +%\def\tabs{\parsearg\tabszzz} +%\def\tabszzz #1{\settabs\+#1\cr} +%\def\tabline{\parsearg\tablinezzz} +%\def\tablinezzz #1{\+#1\cr} +%\def\&{&} + +% Tables -- @table, @ftable, @vtable, @item(x), @kitem(x), @xitem(x). + +% default indentation of table text +\newdimen\tableindent \tableindent=.8in +% default indentation of @itemize and @enumerate text +\newdimen\itemindent \itemindent=.3in +% margin between end of table item and start of table text. +\newdimen\itemmargin \itemmargin=.1in + +% used internally for \itemindent minus \itemmargin +\newdimen\itemmax + +% Note @table, @vtable, and @vtable define @item, @itemx, etc., with +% these defs. +% They also define \itemindex +% to index the item name in whatever manner is desired (perhaps none). + +\newif\ifitemxneedsnegativevskip + +\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi} + +\def\internalBitem{\smallbreak \parsearg\itemzzz} +\def\internalBitemx{\itemxpar \parsearg\itemzzz} + +\def\internalBxitem "#1"{\def\xitemsubtopix{#1} \smallbreak \parsearg\xitemzzz} +\def\internalBxitemx "#1"{\def\xitemsubtopix{#1} \itemxpar \parsearg\xitemzzz} + +\def\internalBkitem{\smallbreak \parsearg\kitemzzz} +\def\internalBkitemx{\itemxpar \parsearg\kitemzzz} + +\def\kitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \lastfunction}}% + \itemzzz {#1}} + +\def\xitemzzz #1{\dosubind {kw}{\code{#1}}{for {\bf \xitemsubtopic}}% + \itemzzz {#1}} + +\def\itemzzz #1{\begingroup % + \advance\hsize by -\rightskip + \advance\hsize by -\tableindent + \setbox0=\hbox{\itemfont{#1}}% + \itemindex{#1}% + \nobreak % This prevents a break before @itemx. + % + % Be sure we are not still in the middle of a paragraph. + %{\parskip = 0in + %\par + %}% + % + % If the item text does not fit in the space we have, put it on a line + % by itself, and do not allow a page break either before or after that + % line. We do not start a paragraph here because then if the next + % command is, e.g., @kindex, the whatsit would get put into the + % horizontal list on a line by itself, resulting in extra blank space. + \ifdim \wd0>\itemmax + % + % Make this a paragraph so we get the \parskip glue and wrapping, + % but leave it ragged-right. + \begingroup + \advance\leftskip by-\tableindent + \advance\hsize by\tableindent + \advance\rightskip by0pt plus1fil + \leavevmode\unhbox0\par + \endgroup + % + % We're going to be starting a paragraph, but we don't want the + % \parskip glue -- logically it's part of the @item we just started. + \nobreak \vskip-\parskip + % + % Stop a page break at the \parskip glue coming up. Unfortunately + % we can't prevent a possible page break at the following + % \baselineskip glue. + \nobreak + \endgroup + \itemxneedsnegativevskipfalse + \else + % The item text fits into the space. Start a paragraph, so that the + % following text (if any) will end up on the same line. Since that + % text will be indented by \tableindent, we make the item text be in + % a zero-width box. + \noindent + \rlap{\hskip -\tableindent\box0}\ignorespaces% + \endgroup% + \itemxneedsnegativevskiptrue% + \fi +} + +\def\item{\errmessage{@item while not in a table}} +\def\itemx{\errmessage{@itemx while not in a table}} +\def\kitem{\errmessage{@kitem while not in a table}} +\def\kitemx{\errmessage{@kitemx while not in a table}} +\def\xitem{\errmessage{@xitem while not in a table}} +\def\xitemx{\errmessage{@xitemx while not in a table}} + +%% Contains a kludge to get @end[description] to work +\def\description{\tablez{\dontindex}{1}{}{}{}{}} + +\def\table{\begingroup\inENV\obeylines\obeyspaces\tablex} +{\obeylines\obeyspaces% +\gdef\tablex #1^^M{% +\tabley\dontindex#1 \endtabley}} + +\def\ftable{\begingroup\inENV\obeylines\obeyspaces\ftablex} +{\obeylines\obeyspaces% +\gdef\ftablex #1^^M{% +\tabley\fnitemindex#1 \endtabley +\def\Eftable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\vtable{\begingroup\inENV\obeylines\obeyspaces\vtablex} +{\obeylines\obeyspaces% +\gdef\vtablex #1^^M{% +\tabley\vritemindex#1 \endtabley +\def\Evtable{\endgraf\afterenvbreak\endgroup}% +\let\Etable=\relax}} + +\def\dontindex #1{} +\def\fnitemindex #1{\doind {fn}{\code{#1}}}% +\def\vritemindex #1{\doind {vr}{\code{#1}}}% + +{\obeyspaces % +\gdef\tabley#1#2 #3 #4 #5 #6 #7\endtabley{\endgroup% +\tablez{#1}{#2}{#3}{#4}{#5}{#6}}} + +\def\tablez #1#2#3#4#5#6{% +\aboveenvbreak % +\begingroup % +\def\Edescription{\Etable}% Necessary kludge. +\let\itemindex=#1% +\ifnum 0#3>0 \advance \leftskip by #3\mil \fi % +\ifnum 0#4>0 \tableindent=#4\mil \fi % +\ifnum 0#5>0 \advance \rightskip by #5\mil \fi % +\def\itemfont{#2}% +\itemmax=\tableindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \tableindent % +\exdentamount=\tableindent +\parindent = 0pt +\parskip = \smallskipamount +\ifdim \parskip=0pt \parskip=2pt \fi% +\def\Etable{\endgraf\afterenvbreak\endgroup}% +\let\item = \internalBitem % +\let\itemx = \internalBitemx % +\let\kitem = \internalBkitem % +\let\kitemx = \internalBkitemx % +\let\xitem = \internalBxitem % +\let\xitemx = \internalBxitemx % +} + +% This is the counter used by @enumerate, which is really @itemize + +\newcount \itemno + +\def\itemize{\parsearg\itemizezzz} + +\def\itemizezzz #1{% + \begingroup % ended by the @end itemsize + \itemizey {#1}{\Eitemize} +} + +\def\itemizey #1#2{% +\aboveenvbreak % +\itemmax=\itemindent % +\advance \itemmax by -\itemmargin % +\advance \leftskip by \itemindent % +\exdentamount=\itemindent +\parindent = 0pt % +\parskip = \smallskipamount % +\ifdim \parskip=0pt \parskip=2pt \fi% +\def#2{\endgraf\afterenvbreak\endgroup}% +\def\itemcontents{#1}% +\let\item=\itemizeitem} + +% Set sfcode to normal for the chars that usually have another value. +% These are `.?!:;,' +\def\frenchspacing{\sfcode46=1000 \sfcode63=1000 \sfcode33=1000 + \sfcode58=1000 \sfcode59=1000 \sfcode44=1000 } + +% \splitoff TOKENS\endmark defines \first to be the first token in +% TOKENS, and \rest to be the remainder. +% +\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}% + +% Allow an optional argument of an uppercase letter, lowercase letter, +% or number, to specify the first label in the enumerated list. No +% argument is the same as `1'. +% +\def\enumerate{\parsearg\enumeratezzz} +\def\enumeratezzz #1{\enumeratey #1 \endenumeratey} +\def\enumeratey #1 #2\endenumeratey{% + \begingroup % ended by the @end enumerate + % + % If we were given no argument, pretend we were given `1'. + \def\thearg{#1}% + \ifx\thearg\empty \def\thearg{1}\fi + % + % Detect if the argument is a single token. If so, it might be a + % letter. Otherwise, the only valid thing it can be is a number. + % (We will always have one token, because of the test we just made. + % This is a good thing, since \splitoff doesn't work given nothing at + % all -- the first parameter is undelimited.) + \expandafter\splitoff\thearg\endmark + \ifx\rest\empty + % Only one token in the argument. It could still be anything. + % A ``lowercase letter'' is one whose \lccode is nonzero. + % An ``uppercase letter'' is one whose \lccode is both nonzero, and + % not equal to itself. + % Otherwise, we assume it's a number. + % + % We need the \relax at the end of the \ifnum lines to stop TeX from + % continuing to look for a <number>. + % + \ifnum\lccode\expandafter`\thearg=0\relax + \numericenumerate % a number (we hope) + \else + % It's a letter. + \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax + \lowercaseenumerate % lowercase letter + \else + \uppercaseenumerate % uppercase letter + \fi + \fi + \else + % Multiple tokens in the argument. We hope it's a number. + \numericenumerate + \fi +} + +% An @enumerate whose labels are integers. The starting integer is +% given in \thearg. +% +\def\numericenumerate{% + \itemno = \thearg + \startenumeration{\the\itemno}% +} + +% The starting (lowercase) letter is in \thearg. +\def\lowercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more lowercase letters in @enumerate; get a bigger + alphabet}% + \fi + \char\lccode\itemno + }% +} + +% The starting (uppercase) letter is in \thearg. +\def\uppercaseenumerate{% + \itemno = \expandafter`\thearg + \startenumeration{% + % Be sure we're not beyond the end of the alphabet. + \ifnum\itemno=0 + \errmessage{No more uppercase letters in @enumerate; get a bigger + alphabet} + \fi + \char\uccode\itemno + }% +} + +% Call itemizey, adding a period to the first argument and supplying the +% common last two arguments. Also subtract one from the initial value in +% \itemno, since @item increments \itemno. +% +\def\startenumeration#1{% + \advance\itemno by -1 + \itemizey{#1.}\Eenumerate\flushcr +} + +% @alphaenumerate and @capsenumerate are abbreviations for giving an arg +% to @enumerate. +% +\def\alphaenumerate{\enumerate{a}} +\def\capsenumerate{\enumerate{A}} +\def\Ealphaenumerate{\Eenumerate} +\def\Ecapsenumerate{\Eenumerate} + +% Definition of @item while inside @itemize. + +\def\itemizeitem{% +\advance\itemno by 1 +{\let\par=\endgraf \smallbreak}% +\ifhmode \errmessage{In hmode at itemizeitem}\fi +{\parskip=0in \hskip 0pt +\hbox to 0pt{\hss \itemcontents\hskip \itemmargin}% +\vadjust{\penalty 1200}}% +\flushcr} + +% @multitable macros +% Amy Hendrickson, 8/18/94, 3/6/96 +% +% @multitable ... @end multitable will make as many columns as desired. +% Contents of each column will wrap at width given in preamble. Width +% can be specified either with sample text given in a template line, +% or in percent of \hsize, the current width of text on page. + +% Table can continue over pages but will only break between lines. + +% To make preamble: +% +% Either define widths of columns in terms of percent of \hsize: +% @multitable @columnfractions .25 .3 .45 +% @item ... +% +% Numbers following @columnfractions are the percent of the total +% current hsize to be used for each column. You may use as many +% columns as desired. + + +% Or use a template: +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item ... +% using the widest term desired in each column. +% +% For those who want to use more than one line's worth of words in +% the preamble, break the line within one argument and it +% will parse correctly, i.e., +% +% @multitable {Column 1 template} {Column 2 template} {Column 3 +% template} +% Not: +% @multitable {Column 1 template} {Column 2 template} +% {Column 3 template} + +% Each new table line starts with @item, each subsequent new column +% starts with @tab. Empty columns may be produced by supplying @tab's +% with nothing between them for as many times as empty columns are needed, +% ie, @tab@tab@tab will produce two empty columns. + +% @item, @tab, @multitable or @end multitable do not need to be on their +% own lines, but it will not hurt if they are. + +% Sample multitable: + +% @multitable {Column 1 template} {Column 2 template} {Column 3 template} +% @item first col stuff @tab second col stuff @tab third col +% @item +% first col stuff +% @tab +% second col stuff +% @tab +% third col +% @item first col stuff @tab second col stuff +% @tab Many paragraphs of text may be used in any column. +% +% They will wrap at the width determined by the template. +% @item@tab@tab This will be in third column. +% @end multitable + +% Default dimensions may be reset by user. +% @multitableparskip is vertical space between paragraphs in table. +% @multitableparindent is paragraph indent in table. +% @multitablecolmargin is horizontal space to be left between columns. +% @multitablelinespace is space to leave between table items, baseline +% to baseline. +% 0pt means it depends on current normal line spacing. + +%%%% +% Dimensions + +\newskip\multitableparskip +\newskip\multitableparindent +\newdimen\multitablecolspace +\newskip\multitablelinespace +\multitableparskip=0pt +\multitableparindent=6pt +\multitablecolspace=12pt +\multitablelinespace=0pt + +%%%% +% Macros used to set up halign preamble: +\let\endsetuptable\relax +\def\xendsetuptable{\endsetuptable} +\let\columnfractions\relax +\def\xcolumnfractions{\columnfractions} +\newif\ifsetpercent + +%% 2/1/96, to allow fractions to be given with more than one digit. +\def\pickupwholefraction#1 {\global\advance\colcount by1 % +\expandafter\xdef\csname col\the\colcount\endcsname{.#1\hsize}% +\setuptable} + +\newcount\colcount +\def\setuptable#1{\def\firstarg{#1}% +\ifx\firstarg\xendsetuptable\let\go\relax% +\else + \ifx\firstarg\xcolumnfractions\global\setpercenttrue% + \else + \ifsetpercent + \let\go\pickupwholefraction % In this case arg of setuptable + % is the decimal point before the + % number given in percent of hsize. + % We don't need this so we don't use it. + \else + \global\advance\colcount by1 + \setbox0=\hbox{#1 }% Add a normal word space as a separator; + % typically that is always in the input, anyway. + \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}% + \fi% + \fi% +\ifx\go\pickupwholefraction\else\let\go\setuptable\fi% +\fi\go} + +%%%% +% multitable syntax +\def\tab{&\hskip1sp\relax} % 2/2/96 + % tiny skip here makes sure this column space is + % maintained, even if it is never used. + + +%%%% +% @multitable ... @end multitable definitions: + +\def\multitable{\parsearg\dotable} + +\def\dotable#1{\bgroup +\let\item\cr +\tolerance=9500 +\hbadness=9500 +\setmultitablespacing +\parskip=\multitableparskip +\parindent=\multitableparindent +\overfullrule=0pt +\global\colcount=0\relax% +\def\Emultitable{\global\setpercentfalse\global\everycr{}\cr\egroup\egroup}% + % To parse everything between @multitable and @item : +\setuptable#1 \endsetuptable + % Need to reset this to 0 after \setuptable. +\global\colcount=0\relax% + % + % This preamble sets up a generic column definition, which will + % be used as many times as user calls for columns. + % \vtop will set a single line and will also let text wrap and + % continue for many paragraphs if desired. +\halign\bgroup&\global\advance\colcount by 1\relax% +\multistrut\vtop{\hsize=\expandafter\csname col\the\colcount\endcsname + % In order to keep entries from bumping into each other + % we will add a \leftskip of \multitablecolspace to all columns after + % the first one. + % If a template has been used, we will add \multitablecolspace + % to the width of each template entry. + % If user has set preamble in terms of percent of \hsize + % we will use that dimension as the width of the column, and + % the \leftskip will keep entries from bumping into each other. + % Table will start at left margin and final column will justify at + % right margin. +\ifnum\colcount=1 +\else + \ifsetpercent + \else + % If user has <not> set preamble in terms of percent of \hsize + % we will advance \hsize by \multitablecolspace + \advance\hsize by \multitablecolspace + \fi + % In either case we will make \leftskip=\multitablecolspace: +\leftskip=\multitablecolspace +\fi + % Ignoring space at the beginning and end avoids an occasional spurious + % blank line, when TeX decides to break the line at the space before the + % box from the multistrut, so the strut ends up on a line by itself. + % For example: + % @multitable @columnfractions .11 .89 + % @item @code{#} + % @tab Legal holiday which is valid in major parts of the whole country. + % Is automatically provided with highlighting sequences respectively marking + % characters. + \noindent\ignorespaces##\unskip\multistrut}\cr + % \everycr will reset column counter, \colcount, at the end of + % each line. Every column entry will cause \colcount to advance by one. + % The table preamble + % looks at the current \colcount to find the correct column width. +\global\everycr{\noalign{% +% \filbreak%% keeps underfull box messages off when table breaks over pages. +% Maybe so, but it also creates really weird page breaks when the table +% breaks over pages Wouldn't \vfil be better? Wait until the problem +% manifests itself, so it can be fixed for real --karl. +\global\colcount=0\relax}} +} + +\def\setmultitablespacing{% test to see if user has set \multitablelinespace. +% If so, do nothing. If not, give it an appropriate dimension based on +% current baselineskip. +\ifdim\multitablelinespace=0pt +%% strut to put in table in case some entry doesn't have descenders, +%% to keep lines equally spaced +\let\multistrut = \strut +%% Test to see if parskip is larger than space between lines of +%% table. If not, do nothing. +%% If so, set to same dimension as multitablelinespace. +\else +\gdef\multistrut{\vrule height\multitablelinespace depth\dp0 +width0pt\relax} \fi +\ifdim\multitableparskip>\multitablelinespace +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi% +\ifdim\multitableparskip=0pt +\global\multitableparskip=\multitablelinespace +\global\advance\multitableparskip-7pt %% to keep parskip somewhat smaller + %% than skip between lines in the table. +\fi} + + +\message{indexing,} +% Index generation facilities + +% Define \newwrite to be identical to plain tex's \newwrite +% except not \outer, so it can be used within \newindex. +{\catcode`\@=11 +\gdef\newwrite{\alloc@7\write\chardef\sixt@@n}} + +% \newindex {foo} defines an index named foo. +% It automatically defines \fooindex such that +% \fooindex ...rest of line... puts an entry in the index foo. +% It also defines \fooindfile to be the number of the output channel for +% the file that accumulates this index. The file's extension is foo. +% The name of an index should be no more than 2 characters long +% for the sake of vms. + +\def\newindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#1}} +} + +% @defindex foo == \newindex{foo} + +\def\defindex{\parsearg\newindex} + +% Define @defcodeindex, like @defindex except put all entries in @code. + +\def\newcodeindex #1{ +\expandafter\newwrite \csname#1indfile\endcsname% Define number for output file +\openout \csname#1indfile\endcsname \jobname.#1 % Open the file +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#1}} +} + +\def\defcodeindex{\parsearg\newcodeindex} + +% @synindex foo bar makes index foo feed into index bar. +% Do this instead of @defindex foo if you don't want it as a separate index. +\def\synindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\doindex {#2}}% +} + +% @syncodeindex foo bar similar, but put all entries made for index foo +% inside @code. +\def\syncodeindex #1 #2 {% +\expandafter\let\expandafter\synindexfoo\expandafter=\csname#2indfile\endcsname +\expandafter\let\csname#1indfile\endcsname=\synindexfoo +\expandafter\xdef\csname#1index\endcsname{% % Define \xxxindex +\noexpand\docodeindex {#2}}% +} + +% Define \doindex, the driver for all \fooindex macros. +% Argument #1 is generated by the calling \fooindex macro, +% and it is "foo", the name of the index. + +% \doindex just uses \parsearg; it calls \doind for the actual work. +% This is because \doind is more useful to call from other macros. + +% There is also \dosubind {index}{topic}{subtopic} +% which makes an entry in a two-level index such as the operation index. + +\def\doindex#1{\edef\indexname{#1}\parsearg\singleindexer} +\def\singleindexer #1{\doind{\indexname}{#1}} + +% like the previous two, but they put @code around the argument. +\def\docodeindex#1{\edef\indexname{#1}\parsearg\singlecodeindexer} +\def\singlecodeindexer #1{\doind{\indexname}{\code{#1}}} + +\def\indexdummies{% +% Take care of the plain tex accent commands. +\def\"{\realbackslash "}% +\def\`{\realbackslash `}% +\def\'{\realbackslash '}% +\def\^{\realbackslash ^}% +\def\~{\realbackslash ~}% +\def\={\realbackslash =}% +\def\b{\realbackslash b}% +\def\c{\realbackslash c}% +\def\d{\realbackslash d}% +\def\u{\realbackslash u}% +\def\v{\realbackslash v}% +\def\H{\realbackslash H}% +% Take care of the plain tex special European modified letters. +\def\oe{\realbackslash oe}% +\def\ae{\realbackslash ae}% +\def\aa{\realbackslash aa}% +\def\OE{\realbackslash OE}% +\def\AE{\realbackslash AE}% +\def\AA{\realbackslash AA}% +\def\o{\realbackslash o}% +\def\O{\realbackslash O}% +\def\l{\realbackslash l}% +\def\L{\realbackslash L}% +\def\ss{\realbackslash ss}% +% Take care of texinfo commands likely to appear in an index entry. +% (Must be a way to avoid doing expansion at all, and thus not have to +% laboriously list every single command here.) +\def\@{@}% will be @@ when we switch to @ as escape char. +%\let\{ = \lbracecmd +%\let\} = \rbracecmd +\def\_{{\realbackslash _}}% +\def\w{\realbackslash w }% +\def\bf{\realbackslash bf }% +%\def\rm{\realbackslash rm }% +\def\sl{\realbackslash sl }% +\def\sf{\realbackslash sf}% +\def\tt{\realbackslash tt}% +\def\gtr{\realbackslash gtr}% +\def\less{\realbackslash less}% +\def\hat{\realbackslash hat}% +%\def\char{\realbackslash char}% +\def\TeX{\realbackslash TeX}% +\def\dots{\realbackslash dots }% +\def\result{\realbackslash result}% +\def\equiv{\realbackslash equiv}% +\def\expansion{\realbackslash expansion}% +\def\print{\realbackslash print}% +\def\error{\realbackslash error}% +\def\point{\realbackslash point}% +\def\copyright{\realbackslash copyright}% +\def\tclose##1{\realbackslash tclose {##1}}% +\def\code##1{\realbackslash code {##1}}% +\def\dotless##1{\realbackslash dotless {##1}}% +\def\samp##1{\realbackslash samp {##1}}% +\def\,##1{\realbackslash ,{##1}}% +\def\t##1{\realbackslash t {##1}}% +\def\r##1{\realbackslash r {##1}}% +\def\i##1{\realbackslash i {##1}}% +\def\b##1{\realbackslash b {##1}}% +\def\sc##1{\realbackslash sc {##1}}% +\def\cite##1{\realbackslash cite {##1}}% +\def\key##1{\realbackslash key {##1}}% +\def\file##1{\realbackslash file {##1}}% +\def\var##1{\realbackslash var {##1}}% +\def\kbd##1{\realbackslash kbd {##1}}% +\def\dfn##1{\realbackslash dfn {##1}}% +\def\emph##1{\realbackslash emph {##1}}% +\def\value##1{\realbackslash value {##1}}% +\unsepspaces +} + +% If an index command is used in an @example environment, any spaces +% therein should become regular spaces in the raw index file, not the +% expansion of \tie (\\leavevmode \penalty \@M \ ). +{\obeyspaces + \gdef\unsepspaces{\obeyspaces\let =\space}} + +% \indexnofonts no-ops all font-change commands. +% This is used when outputting the strings to sort the index by. +\def\indexdummyfont#1{#1} +\def\indexdummytex{TeX} +\def\indexdummydots{...} + +\def\indexnofonts{% +% Just ignore accents. +\let\,=\indexdummyfont +\let\"=\indexdummyfont +\let\`=\indexdummyfont +\let\'=\indexdummyfont +\let\^=\indexdummyfont +\let\~=\indexdummyfont +\let\==\indexdummyfont +\let\b=\indexdummyfont +\let\c=\indexdummyfont +\let\d=\indexdummyfont +\let\u=\indexdummyfont +\let\v=\indexdummyfont +\let\H=\indexdummyfont +\let\dotless=\indexdummyfont +% Take care of the plain tex special European modified letters. +\def\oe{oe}% +\def\ae{ae}% +\def\aa{aa}% +\def\OE{OE}% +\def\AE{AE}% +\def\AA{AA}% +\def\o{o}% +\def\O{O}% +\def\l{l}% +\def\L{L}% +\def\ss{ss}% +\let\w=\indexdummyfont +\let\t=\indexdummyfont +\let\r=\indexdummyfont +\let\i=\indexdummyfont +\let\b=\indexdummyfont +\let\emph=\indexdummyfont +\let\strong=\indexdummyfont +\let\cite=\indexdummyfont +\let\sc=\indexdummyfont +%Don't no-op \tt, since it isn't a user-level command +% and is used in the definitions of the active chars like <, >, |... +%\let\tt=\indexdummyfont +\let\tclose=\indexdummyfont +\let\code=\indexdummyfont +\let\file=\indexdummyfont +\let\samp=\indexdummyfont +\let\kbd=\indexdummyfont +\let\key=\indexdummyfont +\let\var=\indexdummyfont +\let\TeX=\indexdummytex +\let\dots=\indexdummydots +\def\@{@}% +} + +% To define \realbackslash, we must make \ not be an escape. +% We must first make another character (@) an escape +% so we do not become unable to do a definition. + +{\catcode`\@=0 \catcode`\\=\other +@gdef@realbackslash{\}} + +\let\indexbackslash=0 %overridden during \printindex. + +\let\SETmarginindex=\relax %initialize! +% workhorse for all \fooindexes +% #1 is name of index, #2 is stuff to put there +\def\doind #1#2{% + % Put the index entry in the margin if desired. + \ifx\SETmarginindex\relax\else + \insert\margin{\hbox{\vrule height8pt depth3pt width0pt #2}}% + \fi + {% + \count255=\lastpenalty + {% + \indexdummies % Must do this here, since \bf, etc expand at this stage + \escapechar=`\\ + {% + \let\folio=0% We will expand all macros now EXCEPT \folio. + \def\rawbackslashxx{\indexbackslash}% \indexbackslash isn't defined now + % so it will be output as is; and it will print as backslash. + % + % First process the index-string with all font commands turned off + % to get the string to sort by. + {\indexnofonts \xdef\indexsorttmp{#2}}% + % + % Now produce the complete index entry, with both the sort key and the + % original text, including any font commands. + \toks0 = {#2}% + \edef\temp{% + \write\csname#1indfile\endcsname{% + \realbackslash entry{\indexsorttmp}{\folio}{\the\toks0}}% + }% + \temp + }% + }% + \penalty\count255 + }% +} + +\def\dosubind #1#2#3{% +{\count10=\lastpenalty % +{\indexdummies % Must do this here, since \bf, etc expand at this stage +\escapechar=`\\% +{\let\folio=0% +\def\rawbackslashxx{\indexbackslash}% +% +% Now process the index-string once, with all font commands turned off, +% to get the string to sort the index by. +{\indexnofonts +\xdef\temp1{#2 #3}% +}% +% Now produce the complete index entry. We process the index-string again, +% this time with font commands expanded, to get what to print in the index. +\edef\temp{% +\write \csname#1indfile\endcsname{% +\realbackslash entry {\temp1}{\folio}{#2}{#3}}}% +\temp }% +}\penalty\count10}} + +% The index entry written in the file actually looks like +% \entry {sortstring}{page}{topic} +% or +% \entry {sortstring}{page}{topic}{subtopic} +% The texindex program reads in these files and writes files +% containing these kinds of lines: +% \initial {c} +% before the first topic whose initial is c +% \entry {topic}{pagelist} +% for a topic that is used without subtopics +% \primary {topic} +% for the beginning of a topic that is used with subtopics +% \secondary {subtopic}{pagelist} +% for each subtopic. + +% Define the user-accessible indexing commands +% @findex, @vindex, @kindex, @cindex. + +\def\findex {\fnindex} +\def\kindex {\kyindex} +\def\cindex {\cpindex} +\def\vindex {\vrindex} +\def\tindex {\tpindex} +\def\pindex {\pgindex} + +\def\cindexsub {\begingroup\obeylines\cindexsub} +{\obeylines % +\gdef\cindexsub "#1" #2^^M{\endgroup % +\dosubind{cp}{#2}{#1}}} + +% Define the macros used in formatting output of the sorted index material. + +% @printindex causes a particular index (the ??s file) to get printed. +% It does not print any chapter heading (usually an @unnumbered). +% +\def\printindex{\parsearg\doprintindex} +\def\doprintindex#1{\begingroup + \dobreak \chapheadingskip{10000}% + % + \indexfonts \rm + \tolerance = 9500 + \indexbreaks + % + % See if the index file exists and is nonempty. + \openin 1 \jobname.#1s + \ifeof 1 + % \enddoublecolumns gets confused if there is no text in the index, + % and it loses the chapter title and the aux file entries for the + % index. The easiest way to prevent this problem is to make sure + % there is some text. + (Index is nonexistent) + \else + % + % If the index file exists but is empty, then \openin leaves \ifeof + % false. We have to make TeX try to read something from the file, so + % it can discover if there is anything in it. + \read 1 to \temp + \ifeof 1 + (Index is empty) + \else + % Index files are almost Texinfo source, but we use \ as the escape + % character. It would be better to use @, but that's too big a change + % to make right now. + \def\indexbackslash{\rawbackslashxx}% + \catcode`\\ = 0 + \catcode`\@ = 11 + \escapechar = `\\ + \begindoublecolumns + \input \jobname.#1s + \enddoublecolumns + \fi + \fi + \closein 1 +\endgroup} + +% These macros are used by the sorted index file itself. +% Change them to control the appearance of the index. + +% Same as \bigskipamount except no shrink. +% \balancecolumns gets confused if there is any shrink. +\newskip\initialskipamount \initialskipamount 12pt plus4pt + +\def\initial #1{% +{\let\tentt=\sectt \let\tt=\sectt \let\sf=\sectt +\ifdim\lastskip<\initialskipamount +\removelastskip \penalty-200 \vskip \initialskipamount\fi +\line{\secbf#1\hfill}\kern 2pt\penalty10000}} + +% This typesets a paragraph consisting of #1, dot leaders, and then #2 +% flush to the right margin. It is used for index and table of contents +% entries. The paragraph is indented by \leftskip. +% +\def\entry #1#2{\begingroup + % + % Start a new paragraph if necessary, so our assignments below can't + % affect previous text. + \par + % + % Do not fill out the last line with white space. + \parfillskip = 0in + % + % No extra space above this paragraph. + \parskip = 0in + % + % Do not prefer a separate line ending with a hyphen to fewer lines. + \finalhyphendemerits = 0 + % + % \hangindent is only relevant when the entry text and page number + % don't both fit on one line. In that case, bob suggests starting the + % dots pretty far over on the line. Unfortunately, a large + % indentation looks wrong when the entry text itself is broken across + % lines. So we use a small indentation and put up with long leaders. + % + % \hangafter is reset to 1 (which is the value we want) at the start + % of each paragraph, so we need not do anything with that. + \hangindent=2em + % + % When the entry text needs to be broken, just fill out the first line + % with blank space. + \rightskip = 0pt plus1fil + % + % Start a ``paragraph'' for the index entry so the line breaking + % parameters we've set above will have an effect. + \noindent + % + % Insert the text of the index entry. TeX will do line-breaking on it. + #1% + % The following is kludged to not output a line of dots in the index if + % there are no page numbers. The next person who breaks this will be + % cursed by a Unix daemon. + \def\tempa{{\rm }}% + \def\tempb{#2}% + \edef\tempc{\tempa}% + \edef\tempd{\tempb}% + \ifx\tempc\tempd\ \else% + % + % If we must, put the page number on a line of its own, and fill out + % this line with blank space. (The \hfil is overwhelmed with the + % fill leaders glue in \indexdotfill if the page number does fit.) + \hfil\penalty50 + \null\nobreak\indexdotfill % Have leaders before the page number. + % + % The `\ ' here is removed by the implicit \unskip that TeX does as + % part of (the primitive) \par. Without it, a spurious underfull + % \hbox ensues. + \ #2% The page number ends the paragraph. + \fi% + \par +\endgroup} + +% Like \dotfill except takes at least 1 em. +\def\indexdotfill{\cleaders + \hbox{$\mathsurround=0pt \mkern1.5mu ${\it .}$ \mkern1.5mu$}\hskip 1em plus 1fill} + +\def\primary #1{\line{#1\hfil}} + +\newskip\secondaryindent \secondaryindent=0.5cm + +\def\secondary #1#2{ +{\parfillskip=0in \parskip=0in +\hangindent =1in \hangafter=1 +\noindent\hskip\secondaryindent\hbox{#1}\indexdotfill #2\par +}} + +% Define two-column mode, which we use to typeset indexes. +% Adapted from the TeXbook, page 416, which is to say, +% the manmac.tex format used to print the TeXbook itself. +\catcode`\@=11 + +\newbox\partialpage +\newdimen\doublecolumnhsize + +\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns + % Grab any single-column material above us. + \output = {\global\setbox\partialpage = \vbox{% + % + % Here is a possibility not foreseen in manmac: if we accumulate a + % whole lot of material, we might end up calling this \output + % routine twice in a row (see the doublecol-lose test, which is + % essentially a couple of indexes with @setchapternewpage off). In + % that case, we must prevent the second \partialpage from + % simply overwriting the first, causing us to lose the page. + % This will preserve it until a real output routine can ship it + % out. Generally, \partialpage will be empty when this runs and + % this will be a no-op. + \unvbox\partialpage + % + % Unvbox the main output page. + \unvbox255 + \kern-\topskip \kern\baselineskip + }}% + \eject + % + % Use the double-column output routine for subsequent pages. + \output = {\doublecolumnout}% + % + % Change the page size parameters. We could do this once outside this + % routine, in each of @smallbook, @afourpaper, and the default 8.5x11 + % format, but then we repeat the same computation. Repeating a couple + % of assignments once per index is clearly meaningless for the + % execution time, so we may as well do it in one place. + % + % First we halve the line length, less a little for the gutter between + % the columns. We compute the gutter based on the line length, so it + % changes automatically with the paper format. The magic constant + % below is chosen so that the gutter has the same value (well, +-<1pt) + % as it did when we hard-coded it. + % + % We put the result in a separate register, \doublecolumhsize, so we + % can restore it in \pagesofar, after \hsize itself has (potentially) + % been clobbered. + % + \doublecolumnhsize = \hsize + \advance\doublecolumnhsize by -.04154\hsize + \divide\doublecolumnhsize by 2 + \hsize = \doublecolumnhsize + % + % Double the \vsize as well. (We don't need a separate register here, + % since nobody clobbers \vsize.) + \vsize = 2\vsize +} +\def\doublecolumnout{% + \splittopskip=\topskip \splitmaxdepth=\maxdepth + % Get the available space for the double columns -- the normal + % (undoubled) page height minus any material left over from the + % previous page. + \dimen@=\pageheight \advance\dimen@ by-\ht\partialpage + % box0 will be the left-hand column, box2 the right. + \setbox0=\vsplit255 to\dimen@ \setbox2=\vsplit255 to\dimen@ + \onepageout\pagesofar + \unvbox255 + \penalty\outputpenalty +} +\def\pagesofar{% + % Re-output the contents of the output page -- any previous material, + % followed by the two boxes we just split. + \unvbox\partialpage + \hsize = \doublecolumnhsize + \wd0=\hsize \wd2=\hsize \hbox to\pagewidth{\box0\hfil\box2}% +} +\def\enddoublecolumns{% + \output = {\balancecolumns}\eject % split what we have + \endgroup % started in \begindoublecolumns + % + % Back to normal single-column typesetting, but take account of the + % fact that we just accumulated some stuff on the output page. + \pagegoal = \vsize +} +\def\balancecolumns{% + % Called at the end of the double column material. + \setbox0 = \vbox{\unvbox255}% + \dimen@ = \ht0 + \advance\dimen@ by \topskip + \advance\dimen@ by-\baselineskip + \divide\dimen@ by 2 + \splittopskip = \topskip + % Loop until we get a decent breakpoint. + {\vbadness=10000 \loop + \global\setbox3=\copy0 + \global\setbox1=\vsplit3 to\dimen@ + \ifdim\ht3>\dimen@ \global\advance\dimen@ by1pt + \repeat}% + \setbox0=\vbox to\dimen@{\unvbox1}% + \setbox2=\vbox to\dimen@{\unvbox3}% + \pagesofar +} +\catcode`\@ = \other + + +\message{sectioning,} +% Define chapters, sections, etc. + +\newcount\chapno +\newcount\secno \secno=0 +\newcount\subsecno \subsecno=0 +\newcount\subsubsecno \subsubsecno=0 + +% This counter is funny since it counts through charcodes of letters A, B, ... +\newcount\appendixno \appendixno = `\@ +\def\appendixletter{\char\the\appendixno} + +\newwrite\contentsfile +% This is called from \setfilename. +\def\opencontents{\openout\contentsfile = \jobname.toc } + +% Each @chapter defines this as the name of the chapter. +% page headings and footings can use it. @section does likewise + +\def\thischapter{} \def\thissection{} +\def\seccheck#1{\ifnum \pageno<0 + \errmessage{@#1 not allowed after generating table of contents}% +\fi} + +\def\chapternofonts{% + \let\rawbackslash=\relax + \let\frenchspacing=\relax + \def\result{\realbackslash result}% + \def\equiv{\realbackslash equiv}% + \def\expansion{\realbackslash expansion}% + \def\print{\realbackslash print}% + \def\TeX{\realbackslash TeX}% + \def\dots{\realbackslash dots}% + \def\result{\realbackslash result}% + \def\equiv{\realbackslash equiv}% + \def\expansion{\realbackslash expansion}% + \def\print{\realbackslash print}% + \def\error{\realbackslash error}% + \def\point{\realbackslash point}% + \def\copyright{\realbackslash copyright}% + \def\tt{\realbackslash tt}% + \def\bf{\realbackslash bf}% + \def\w{\realbackslash w}% + \def\less{\realbackslash less}% + \def\gtr{\realbackslash gtr}% + \def\hat{\realbackslash hat}% + \def\char{\realbackslash char}% + \def\tclose##1{\realbackslash tclose{##1}}% + \def\code##1{\realbackslash code{##1}}% + \def\samp##1{\realbackslash samp{##1}}% + \def\r##1{\realbackslash r{##1}}% + \def\b##1{\realbackslash b{##1}}% + \def\key##1{\realbackslash key{##1}}% + \def\file##1{\realbackslash file{##1}}% + \def\kbd##1{\realbackslash kbd{##1}}% + % These are redefined because @smartitalic wouldn't work inside xdef. + \def\i##1{\realbackslash i{##1}}% + \def\cite##1{\realbackslash cite{##1}}% + \def\var##1{\realbackslash var{##1}}% + \def\emph##1{\realbackslash emph{##1}}% + \def\dfn##1{\realbackslash dfn{##1}}% +} + +\newcount\absseclevel % used to calculate proper heading level +\newcount\secbase\secbase=0 % @raise/lowersections modify this count + +% @raisesections: treat @section as chapter, @subsection as section, etc. +\def\raisesections{\global\advance\secbase by -1} +\let\up=\raisesections % original BFox name + +% @lowersections: treat @chapter as section, @section as subsection, etc. +\def\lowersections{\global\advance\secbase by 1} +\let\down=\lowersections % original BFox name + +% Choose a numbered-heading macro +% #1 is heading level if unmodified by @raisesections or @lowersections +% #2 is text for heading +\def\numhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \chapterzzz{#2} +\or + \seczzz{#2} +\or + \numberedsubseczzz{#2} +\or + \numberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \chapterzzz{#2} + \else + \numberedsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses appendix heading levels +\def\apphead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \appendixzzz{#2} +\or + \appendixsectionzzz{#2} +\or + \appendixsubseczzz{#2} +\or + \appendixsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \appendixzzz{#2} + \else + \appendixsubsubseczzz{#2} + \fi +\fi +} + +% like \numhead, but chooses numberless heading levels +\def\unnmhead#1#2{\absseclevel=\secbase\advance\absseclevel by #1 +\ifcase\absseclevel + \unnumberedzzz{#2} +\or + \unnumberedseczzz{#2} +\or + \unnumberedsubseczzz{#2} +\or + \unnumberedsubsubseczzz{#2} +\else + \ifnum \absseclevel<0 + \unnumberedzzz{#2} + \else + \unnumberedsubsubseczzz{#2} + \fi +\fi +} + + +\def\thischaptername{No Chapter Title} +\outer\def\chapter{\parsearg\chapteryyy} +\def\chapteryyy #1{\numhead0{#1}} % normally numhead0 calls chapterzzz +\def\chapterzzz #1{\seccheck{chapter}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \chapno by 1 \message{\putwordChapter \the\chapno}% +\chapmacro {#1}{\the\chapno}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +% We don't substitute the actual chapter name into \thischapter +% because we don't want its macros evaluated now. +\xdef\thischapter{\putwordChapter{} \the\chapno: \noexpand\thischaptername}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash chapentry{\the\toks0}{\the\chapno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec +}} + +\outer\def\appendix{\parsearg\appendixyyy} +\def\appendixyyy #1{\apphead0{#1}} % normally apphead0 calls appendixzzz +\def\appendixzzz #1{\seccheck{appendix}% +\secno=0 \subsecno=0 \subsubsecno=0 +\global\advance \appendixno by 1 \message{Appendix \appendixletter}% +\chapmacro {#1}{\putwordAppendix{} \appendixletter}% +\gdef\thissection{#1}% +\gdef\thischaptername{#1}% +\xdef\thischapter{\putwordAppendix{} \appendixletter: \noexpand\thischaptername}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash chapentry{\the\toks0}% + {\putwordAppendix{} \appendixletter}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\global\let\section = \appendixsec +\global\let\subsection = \appendixsubsec +\global\let\subsubsection = \appendixsubsubsec +}} + +% @centerchap is like @unnumbered, but the heading is centered. +\outer\def\centerchap{\parsearg\centerchapyyy} +\def\centerchapyyy #1{{\let\unnumbchapmacro=\centerchapmacro \unnumberedyyy{#1}}} + +\outer\def\top{\parsearg\unnumberedyyy} +\outer\def\unnumbered{\parsearg\unnumberedyyy} +\def\unnumberedyyy #1{\unnmhead0{#1}} % normally unnmhead0 calls unnumberedzzz +\def\unnumberedzzz #1{\seccheck{unnumbered}% +\secno=0 \subsecno=0 \subsubsecno=0 +% +% This used to be simply \message{#1}, but TeX fully expands the +% argument to \message. Therefore, if #1 contained @-commands, TeX +% expanded them. For example, in `@unnumbered The @cite{Book}', TeX +% expanded @cite (which turns out to cause errors because \cite is meant +% to be executed, not expanded). +% +% Anyway, we don't want the fully-expanded definition of @cite to appear +% as a result of the \message, we just want `@cite' itself. We use +% \the<toks register> to achieve this: TeX expands \the<toks> only once, +% simply yielding the contents of the <toks register>. +\toks0 = {#1}\message{(\the\toks0)}% +% +\unnumbchapmacro {#1}% +\gdef\thischapter{#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbchapentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\global\let\section = \unnumberedsec +\global\let\subsection = \unnumberedsubsec +\global\let\subsubsection = \unnumberedsubsubsec +}} + +\outer\def\numberedsec{\parsearg\secyyy} +\def\secyyy #1{\numhead1{#1}} % normally calls seczzz +\def\seczzz #1{\seccheck{section}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\the\chapno}{\the\secno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash secentry % +{\the\toks0}{\the\chapno}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsection{\parsearg\appendixsecyyy} +\outer\def\appendixsec{\parsearg\appendixsecyyy} +\def\appendixsecyyy #1{\apphead1{#1}} % normally calls appendixsectionzzz +\def\appendixsectionzzz #1{\seccheck{appendixsection}% +\subsecno=0 \subsubsecno=0 \global\advance \secno by 1 % +\gdef\thissection{#1}\secheading {#1}{\appendixletter}{\the\secno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash secentry % +{\the\toks0}{\appendixletter}{\the\secno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsec{\parsearg\unnumberedsecyyy} +\def\unnumberedsecyyy #1{\unnmhead1{#1}} % normally calls unnumberedseczzz +\def\unnumberedseczzz #1{\seccheck{unnumberedsec}% +\plainsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsec{\parsearg\numberedsubsecyyy} +\def\numberedsubsecyyy #1{\numhead2{#1}} % normally calls numberedsubseczzz +\def\numberedsubseczzz #1{\seccheck{subsection}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\the\chapno}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsecentry % +{\the\toks0}{\the\chapno}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsec{\parsearg\appendixsubsecyyy} +\def\appendixsubsecyyy #1{\apphead2{#1}} % normally calls appendixsubseczzz +\def\appendixsubseczzz #1{\seccheck{appendixsubsec}% +\gdef\thissection{#1}\subsubsecno=0 \global\advance \subsecno by 1 % +\subsecheading {#1}{\appendixletter}{\the\secno}{\the\subsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsecentry % +{\the\toks0}{\appendixletter}{\the\secno}{\the\subsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsec{\parsearg\unnumberedsubsecyyy} +\def\unnumberedsubsecyyy #1{\unnmhead2{#1}} %normally calls unnumberedsubseczzz +\def\unnumberedsubseczzz #1{\seccheck{unnumberedsubsec}% +\plainsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsubsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +\outer\def\numberedsubsubsec{\parsearg\numberedsubsubsecyyy} +\def\numberedsubsubsecyyy #1{\numhead3{#1}} % normally numberedsubsubseczzz +\def\numberedsubsubseczzz #1{\seccheck{subsubsection}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsubsecentry{\the\toks0} + {\the\chapno}{\the\secno}{\the\subsecno}{\the\subsubsecno} + {\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\donoderef % +\penalty 10000 % +}} + +\outer\def\appendixsubsubsec{\parsearg\appendixsubsubsecyyy} +\def\appendixsubsubsecyyy #1{\apphead3{#1}} % normally appendixsubsubseczzz +\def\appendixsubsubseczzz #1{\seccheck{appendixsubsubsec}% +\gdef\thissection{#1}\global\advance \subsubsecno by 1 % +\subsubsecheading {#1} + {\appendixletter}{\the\secno}{\the\subsecno}{\the\subsubsecno}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash subsubsecentry{\the\toks0}% + {\appendixletter} + {\the\secno}{\the\subsecno}{\the\subsubsecno}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\appendixnoderef % +\penalty 10000 % +}} + +\outer\def\unnumberedsubsubsec{\parsearg\unnumberedsubsubsecyyy} +\def\unnumberedsubsubsecyyy #1{\unnmhead3{#1}} %normally unnumberedsubsubseczzz +\def\unnumberedsubsubseczzz #1{\seccheck{unnumberedsubsubsec}% +\plainsubsubsecheading {#1}\gdef\thissection{#1}% +{\chapternofonts% +\toks0 = {#1}% +\edef\temp{{\realbackslash unnumbsubsubsecentry{\the\toks0}{\noexpand\folio}}}% +\escapechar=`\\% +\write \contentsfile \temp % +\unnumbnoderef % +\penalty 10000 % +}} + +% These are variants which are not "outer", so they can appear in @ifinfo. +% Actually, they should now be obsolete; ordinary section commands should work. +\def\infotop{\parsearg\unnumberedzzz} +\def\infounnumbered{\parsearg\unnumberedzzz} +\def\infounnumberedsec{\parsearg\unnumberedseczzz} +\def\infounnumberedsubsec{\parsearg\unnumberedsubseczzz} +\def\infounnumberedsubsubsec{\parsearg\unnumberedsubsubseczzz} + +\def\infoappendix{\parsearg\appendixzzz} +\def\infoappendixsec{\parsearg\appendixseczzz} +\def\infoappendixsubsec{\parsearg\appendixsubseczzz} +\def\infoappendixsubsubsec{\parsearg\appendixsubsubseczzz} + +\def\infochapter{\parsearg\chapterzzz} +\def\infosection{\parsearg\sectionzzz} +\def\infosubsection{\parsearg\subsectionzzz} +\def\infosubsubsection{\parsearg\subsubsectionzzz} + +% These macros control what the section commands do, according +% to what kind of chapter we are in (ordinary, appendix, or unnumbered). +% Define them by default for a numbered chapter. +\global\let\section = \numberedsec +\global\let\subsection = \numberedsubsec +\global\let\subsubsection = \numberedsubsubsec + +% Define @majorheading, @heading and @subheading + +% NOTE on use of \vbox for chapter headings, section headings, and +% such: +% 1) We use \vbox rather than the earlier \line to permit +% overlong headings to fold. +% 2) \hyphenpenalty is set to 10000 because hyphenation in a +% heading is obnoxious; this forbids it. +% 3) Likewise, headings look best if no \parindent is used, and +% if justification is not attempted. Hence \raggedright. + + +\def\majorheading{\parsearg\majorheadingzzz} +\def\majorheadingzzz #1{% +{\advance\chapheadingskip by 10pt \chapbreak }% +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +\def\chapheading{\parsearg\chapheadingzzz} +\def\chapheadingzzz #1{\chapbreak % +{\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 200} + +% @heading, @subheading, @subsubheading. +\def\heading{\parsearg\plainsecheading} +\def\subheading{\parsearg\plainsubsecheading} +\def\subsubheading{\parsearg\plainsubsubsecheading} + +% These macros generate a chapter, section, etc. heading only +% (including whitespace, linebreaking, etc. around it), +% given all the information in convenient, parsed form. + +%%% Args are the skip and penalty (usually negative) +\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi} + +\def\setchapterstyle #1 {\csname CHAPF#1\endcsname} + +%%% Define plain chapter starts, and page on/off switching for it +% Parameter controlling skip before chapter headings (if needed) + +\newskip\chapheadingskip + +\def\chapbreak{\dobreak \chapheadingskip {-4000}} +\def\chappager{\par\vfill\supereject} +\def\chapoddpage{\chappager \ifodd\pageno \else \hbox to 0pt{} \chappager\fi} + +\def\setchapternewpage #1 {\csname CHAPPAG#1\endcsname} + +\def\CHAPPAGoff{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chapbreak +\global\let\pagealignmacro=\chappager} + +\def\CHAPPAGon{ +\global\let\contentsalignmacro = \chappager +\global\let\pchapsepmacro=\chappager +\global\let\pagealignmacro=\chappager +\global\def\HEADINGSon{\HEADINGSsingle}} + +\def\CHAPPAGodd{ +\global\let\contentsalignmacro = \chapoddpage +\global\let\pchapsepmacro=\chapoddpage +\global\let\pagealignmacro=\chapoddpage +\global\def\HEADINGSon{\HEADINGSdouble}} + +\CHAPPAGon + +\def\CHAPFplain{ +\global\let\chapmacro=\chfplain +\global\let\unnumbchapmacro=\unnchfplain +\global\let\centerchapmacro=\centerchfplain} + +% Plain chapter opening. +% #1 is the text, #2 the chapter number or empty if unnumbered. +\def\chfplain#1#2{% + \pchapsepmacro + {% + \chapfonts \rm + \def\chapnum{#2}% + \setbox0 = \hbox{#2\ifx\chapnum\empty\else\enspace\fi}% + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 \centerparametersmaybe + \unhbox0 #1\par}% + }% + \nobreak\bigskip % no page break after a chapter title + \nobreak +} + +% Plain opening for unnumbered. +\def\unnchfplain#1{\chfplain{#1}{}} + +% @centerchap -- centered and unnumbered. +\let\centerparametersmaybe = \relax +\def\centerchfplain#1{{% + \def\centerparametersmaybe{% + \advance\rightskip by 3\rightskip + \leftskip = \rightskip + \parfillskip = 0pt + }% + \chfplain{#1}{}% +}} + +\CHAPFplain % The default + +\def\unnchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt\raggedright + \rm #1\hfill}}\bigskip \par\penalty 10000 % +} + +\def\chfopen #1#2{\chapoddpage {\chapfonts +\vbox to 3in{\vfil \hbox to\hsize{\hfil #2} \hbox to\hsize{\hfil #1} \vfil}}% +\par\penalty 5000 % +} + +\def\centerchfopen #1{% +\chapoddpage {\chapfonts \vbox{\hyphenpenalty=10000\tolerance=5000 + \parindent=0pt + \hfill {\rm #1}\hfill}}\bigskip \par\penalty 10000 % +} + +\def\CHAPFopen{ +\global\let\chapmacro=\chfopen +\global\let\unnumbchapmacro=\unnchfopen +\global\let\centerchapmacro=\centerchfopen} + + +% Section titles. +\newskip\secheadingskip +\def\secheadingbreak{\dobreak \secheadingskip {-1000}} +\def\secheading#1#2#3{\sectionheading{sec}{#2.#3}{#1}} +\def\plainsecheading#1{\sectionheading{sec}{}{#1}} + +% Subsection titles. +\newskip \subsecheadingskip +\def\subsecheadingbreak{\dobreak \subsecheadingskip {-500}} +\def\subsecheading#1#2#3#4{\sectionheading{subsec}{#2.#3.#4}{#1}} +\def\plainsubsecheading#1{\sectionheading{subsec}{}{#1}} + +% Subsubsection titles. +\let\subsubsecheadingskip = \subsecheadingskip +\let\subsubsecheadingbreak = \subsecheadingbreak +\def\subsubsecheading#1#2#3#4#5{\sectionheading{subsubsec}{#2.#3.#4.#5}{#1}} +\def\plainsubsubsecheading#1{\sectionheading{subsubsec}{}{#1}} + + +% Print any size section title. +% +% #1 is the section type (sec/subsec/subsubsec), #2 is the section +% number (maybe empty), #3 the text. +\def\sectionheading#1#2#3{% + {% + \expandafter\advance\csname #1headingskip\endcsname by \parskip + \csname #1headingbreak\endcsname + }% + {% + % Switch to the right set of fonts. + \csname #1fonts\endcsname \rm + % + % Only insert the separating space if we have a section number. + \def\secnum{#2}% + \setbox0 = \hbox{#2\ifx\secnum\empty\else\enspace\fi}% + % + \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \raggedright + \hangindent = \wd0 % zero if no section number + \unhbox0 #3}% + }% + \ifdim\parskip<10pt \nobreak\kern10pt\nobreak\kern-\parskip\fi \nobreak +} + + +\message{toc printing,} +% Finish up the main text and prepare to read what we've written +% to \contentsfile. + +\newskip\contentsrightmargin \contentsrightmargin=1in +\def\startcontents#1{% + % If @setchapternewpage on, and @headings double, the contents should + % start on an odd page, unlike chapters. Thus, we maintain + % \contentsalignmacro in parallel with \pagealignmacro. + % From: Torbjorn Granlund <tege@matematik.su.se> + \contentsalignmacro + \immediate\closeout \contentsfile + \ifnum \pageno>0 + \pageno = -1 % Request roman numbered pages. + \fi + % Don't need to put `Contents' or `Short Contents' in the headline. + % It is abundantly clear what they are. + \unnumbchapmacro{#1}\def\thischapter{}% + \begingroup % Set up to handle contents files properly. + \catcode`\\=0 \catcode`\{=1 \catcode`\}=2 \catcode`\@=11 + % We can't do this, because then an actual ^ in a section + % title fails, e.g., @chapter ^ -- exponentiation. --karl, 9jul97. + %\catcode`\^=7 % to see ^^e4 as \"a etc. juha@piuha.ydi.vtt.fi + \raggedbottom % Worry more about breakpoints than the bottom. + \advance\hsize by -\contentsrightmargin % Don't use the full line length. +} + + +% Normal (long) toc. +\outer\def\contents{% + \startcontents{\putwordTableofContents}% + \input \jobname.toc + \endgroup + \vfill \eject +} + +% And just the chapters. +\outer\def\summarycontents{% + \startcontents{\putwordShortContents}% + % + \let\chapentry = \shortchapentry + \let\unnumbchapentry = \shortunnumberedentry + % We want a true roman here for the page numbers. + \secfonts + \let\rm=\shortcontrm \let\bf=\shortcontbf \let\sl=\shortcontsl + \rm + \hyphenpenalty = 10000 + \advance\baselineskip by 1pt % Open it up a little. + \def\secentry ##1##2##3##4{} + \def\unnumbsecentry ##1##2{} + \def\subsecentry ##1##2##3##4##5{} + \def\unnumbsubsecentry ##1##2{} + \def\subsubsecentry ##1##2##3##4##5##6{} + \def\unnumbsubsubsecentry ##1##2{} + \input \jobname.toc + \endgroup + \vfill \eject +} +\let\shortcontents = \summarycontents + +% These macros generate individual entries in the table of contents. +% The first argument is the chapter or section name. +% The last argument is the page number. +% The arguments in between are the chapter number, section number, ... + +% Chapter-level things, for both the long and short contents. +\def\chapentry#1#2#3{\dochapentry{#2\labelspace#1}{#3}} + +% See comments in \dochapentry re vbox and related settings +\def\shortchapentry#1#2#3{% + \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno{#3}}% +} + +% Typeset the label for a chapter or appendix for the short contents. +% The arg is, e.g. `Appendix A' for an appendix, or `3' for a chapter. +% We could simplify the code here by writing out an \appendixentry +% command in the toc file for appendices, instead of using \chapentry +% for both, but it doesn't seem worth it. +\setbox0 = \hbox{\shortcontrm \putwordAppendix } +\newdimen\shortappendixwidth \shortappendixwidth = \wd0 + +\def\shortchaplabel#1{% + % We typeset #1 in a box of constant width, regardless of the text of + % #1, so the chapter titles will come out aligned. + \setbox0 = \hbox{#1}% + \dimen0 = \ifdim\wd0 > \shortappendixwidth \shortappendixwidth \else 0pt \fi + % + % This space should be plenty, since a single number is .5em, and the + % widest letter (M) is 1em, at least in the Computer Modern fonts. + % (This space doesn't include the extra space that gets added after + % the label; that gets put in by \shortchapentry above.) + \advance\dimen0 by 1.1em + \hbox to \dimen0{#1\hfil}% +} + +\def\unnumbchapentry#1#2{\dochapentry{#1}{#2}} +\def\shortunnumberedentry#1#2{\tocentry{#1}{\doshortpageno{#2}}} + +% Sections. +\def\secentry#1#2#3#4{\dosecentry{#2.#3\labelspace#1}{#4}} +\def\unnumbsecentry#1#2{\dosecentry{#1}{#2}} + +% Subsections. +\def\subsecentry#1#2#3#4#5{\dosubsecentry{#2.#3.#4\labelspace#1}{#5}} +\def\unnumbsubsecentry#1#2{\dosubsecentry{#1}{#2}} + +% And subsubsections. +\def\subsubsecentry#1#2#3#4#5#6{% + \dosubsubsecentry{#2.#3.#4.#5\labelspace#1}{#6}} +\def\unnumbsubsubsecentry#1#2{\dosubsubsecentry{#1}{#2}} + +% This parameter controls the indentation of the various levels. +\newdimen\tocindent \tocindent = 3pc + +% Now for the actual typesetting. In all these, #1 is the text and #2 is the +% page number. +% +% If the toc has to be broken over pages, we want it to be at chapters +% if at all possible; hence the \penalty. +\def\dochapentry#1#2{% + \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip + \begingroup + \chapentryfonts + \tocentry{#1}{\dopageno{#2}}% + \endgroup + \nobreak\vskip .25\baselineskip plus.1\baselineskip +} + +\def\dosecentry#1#2{\begingroup + \secentryfonts \leftskip=\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsecentry#1#2{\begingroup + \subsecentryfonts \leftskip=2\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +\def\dosubsubsecentry#1#2{\begingroup + \subsubsecentryfonts \leftskip=3\tocindent + \tocentry{#1}{\dopageno{#2}}% +\endgroup} + +% Final typesetting of a toc entry; we use the same \entry macro as for +% the index entries, but we want to suppress hyphenation here. (We +% can't do that in the \entry macro, since index entries might consist +% of hyphenated-identifiers-that-do-not-fit-on-a-line-and-nothing-else.) +% +% \turnoffactive is for the sake of @" used for umlauts. +\def\tocentry#1#2{\begingroup + \vskip 0pt plus1pt % allow a little stretch for the sake of nice page breaks + \entry{\turnoffactive #1}{\turnoffactive #2}% +\endgroup} + +% Space between chapter (or whatever) number and the title. +\def\labelspace{\hskip1em \relax} + +\def\dopageno#1{{\rm #1}} +\def\doshortpageno#1{{\rm #1}} + +\def\chapentryfonts{\secfonts \rm} +\def\secentryfonts{\textfonts} +\let\subsecentryfonts = \textfonts +\let\subsubsecentryfonts = \textfonts + + +\message{environments,} + +% Since these characters are used in examples, it should be an even number of +% \tt widths. Each \tt character is 1en, so two makes it 1em. +% Furthermore, these definitions must come after we define our fonts. +\newbox\dblarrowbox \newbox\longdblarrowbox +\newbox\pushcharbox \newbox\bullbox +\newbox\equivbox \newbox\errorbox + +%{\tentt +%\global\setbox\dblarrowbox = \hbox to 1em{\hfil$\Rightarrow$\hfil} +%\global\setbox\longdblarrowbox = \hbox to 1em{\hfil$\mapsto$\hfil} +%\global\setbox\pushcharbox = \hbox to 1em{\hfil$\dashv$\hfil} +%\global\setbox\equivbox = \hbox to 1em{\hfil$\ptexequiv$\hfil} +% Adapted from the manmac format (p.420 of TeXbook) +%\global\setbox\bullbox = \hbox to 1em{\kern.15em\vrule height .75ex width .85ex +% depth .1ex\hfil} +%} + +% @point{}, @result{}, @expansion{}, @print{}, @equiv{}. +\def\point{$\star$} +\def\result{\leavevmode\raise.15ex\hbox to 1em{\hfil$\Rightarrow$\hfil}} +\def\expansion{\leavevmode\raise.1ex\hbox to 1em{\hfil$\mapsto$\hfil}} +\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}} +\def\equiv{\leavevmode\lower.1ex\hbox to 1em{\hfil$\ptexequiv$\hfil}} + +% Adapted from the TeXbook's \boxit. +{\tentt \global\dimen0 = 3em}% Width of the box. +\dimen2 = .55pt % Thickness of rules +% The text. (`r' is open on the right, `e' somewhat less so on the left.) +\setbox0 = \hbox{\kern-.75pt \tensf error\kern-1.5pt} + +\global\setbox\errorbox=\hbox to \dimen0{\hfil + \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right. + \advance\hsize by -2\dimen2 % Rules. + \vbox{ + \hrule height\dimen2 + \hbox{\vrule width\dimen2 \kern3pt % Space to left of text. + \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below. + \kern3pt\vrule width\dimen2}% Space to right. + \hrule height\dimen2} + \hfil} + +% The @error{} command. +\def\error{\leavevmode\lower.7ex\copy\errorbox} + +% @tex ... @end tex escapes into raw Tex temporarily. +% One exception: @ is still an escape character, so that @end tex works. +% But \@ or @@ will get a plain tex @ character. + +\def\tex{\begingroup +\catcode `\\=0 \catcode `\{=1 \catcode `\}=2 +\catcode `\$=3 \catcode `\&=4 \catcode `\#=6 +\catcode `\^=7 \catcode `\_=8 \catcode `\~=13 \let~=\tie +\catcode `\%=14 +\catcode 43=12 % plus +\catcode`\"=12 +\catcode`\==12 +\catcode`\|=12 +\catcode`\<=12 +\catcode`\>=12 +\escapechar=`\\ +% +\let\,=\ptexcomma +\let\{=\ptexlbrace +\let\}=\ptexrbrace +\let\.=\ptexdot +\let\*=\ptexstar +\let\dots=\ptexdots +\def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}% +\def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}% +\def\@{@}% +\let\bullet=\ptexbullet +\let\b=\ptexb \let\c=\ptexc \let\i=\ptexi \let\t=\ptext +% +\let\Etex=\endgroup} + +% Define @lisp ... @endlisp. +% @lisp does a \begingroup so it can rebind things, +% including the definition of @endlisp (which normally is erroneous). + +% Amount to narrow the margins by for @lisp. +\newskip\lispnarrowing \lispnarrowing=0.4in + +% This is the definition that ^^M gets inside @lisp, @example, and other +% such environments. \null is better than a space, since it doesn't +% have any width. +\def\lisppar{\null\endgraf} + +% Make each space character in the input produce a normal interword +% space in the output. Don't allow a line break at this space, as this +% is used only in environments like @example, where each line of input +% should produce a line of output anyway. +% +{\obeyspaces % +\gdef\sepspaces{\obeyspaces\let =\tie}} + +% Define \obeyedspace to be our active space, whatever it is. This is +% for use in \parsearg. +{\sepspaces% +\global\let\obeyedspace= } + +% This space is always present above and below environments. +\newskip\envskipamount \envskipamount = 0pt + +% Make spacing and below environment symmetrical. We use \parskip here +% to help in doing that, since in @example-like environments \parskip +% is reset to zero; thus the \afterenvbreak inserts no space -- but the +% start of the next paragraph will insert \parskip +% +\def\aboveenvbreak{{\advance\envskipamount by \parskip +\endgraf \ifdim\lastskip<\envskipamount +\removelastskip \penalty-50 \vskip\envskipamount \fi}} + +\let\afterenvbreak = \aboveenvbreak + +% \nonarrowing is a flag. If "set", @lisp etc don't narrow margins. +\let\nonarrowing=\relax + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% \cartouche: draw rectangle w/rounded corners around argument +\font\circle=lcircle10 +\newdimen\circthick +\newdimen\cartouter\newdimen\cartinner +\newskip\normbskip\newskip\normpskip\newskip\normlskip +\circthick=\fontdimen8\circle +% +\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth +\def\ctr{{\hskip 6pt\circle\char'010}} +\def\cbl{{\circle\char'012\hskip -6pt}} +\def\cbr{{\hskip 6pt\circle\char'011}} +\def\carttop{\hbox to \cartouter{\hskip\lskip + \ctl\leaders\hrule height\circthick\hfil\ctr + \hskip\rskip}} +\def\cartbot{\hbox to \cartouter{\hskip\lskip + \cbl\leaders\hrule height\circthick\hfil\cbr + \hskip\rskip}} +% +\newskip\lskip\newskip\rskip + +\long\def\cartouche{% +\begingroup + \lskip=\leftskip \rskip=\rightskip + \leftskip=0pt\rightskip=0pt %we want these *outside*. + \cartinner=\hsize \advance\cartinner by-\lskip + \advance\cartinner by-\rskip + \cartouter=\hsize + \advance\cartouter by 18pt % allow for 3pt kerns on either +% side, and for 6pt waste from +% each corner char + \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip + % Flag to tell @lisp, etc., not to narrow margin. + \let\nonarrowing=\comment + \vbox\bgroup + \baselineskip=0pt\parskip=0pt\lineskip=0pt + \carttop + \hbox\bgroup + \hskip\lskip + \vrule\kern3pt + \vbox\bgroup + \hsize=\cartinner + \kern3pt + \begingroup + \baselineskip=\normbskip + \lineskip=\normlskip + \parskip=\normpskip + \vskip -\parskip +\def\Ecartouche{% + \endgroup + \kern3pt + \egroup + \kern3pt\vrule + \hskip\rskip + \egroup + \cartbot + \egroup +\endgroup +}} + + +% This macro is called at the beginning of all the @example variants, +% inside a group. +\def\nonfillstart{% + \aboveenvbreak + \inENV % This group ends at the end of the body + \hfuzz = 12pt % Don't be fussy + \sepspaces % Make spaces be word-separators rather than space tokens. + \singlespace + \let\par = \lisppar % don't ignore blank lines + \obeylines % each line of input is a line of output + \parskip = 0pt + \parindent = 0pt + \emergencystretch = 0pt % don't try to avoid overfull boxes + % @cartouche defines \nonarrowing to inhibit narrowing + % at next level down. + \ifx\nonarrowing\relax + \advance \leftskip by \lispnarrowing + \exdentamount=\lispnarrowing + \let\exdent=\nofillexdent + \let\nonarrowing=\relax + \fi +} + +% To ending an @example-like environment, we first end the paragraph +% (via \afterenvbreak's vertical glue), and then the group. That way we +% keep the zero \parskip that the environments set -- \parskip glue +% will be inserted at the beginning of the next paragraph in the +% document, after the environment. +% +\def\nonfillfinish{\afterenvbreak\endgroup}% + +\def\lisp{\begingroup + \nonfillstart + \let\Elisp = \nonfillfinish + \tt + % Make @kbd do something special, if requested. + \let\kbdfont\kbdexamplefont + \rawbackslash % have \ input char produce \ char from current font + \gobble +} + +% Define the \E... control sequence only if we are inside the +% environment, so the error checking in \end will work. +% +% We must call \lisp last in the definition, since it reads the +% return following the @example (or whatever) command. +% +\def\example{\begingroup \def\Eexample{\nonfillfinish\endgroup}\lisp} +\def\smallexample{\begingroup \def\Esmallexample{\nonfillfinish\endgroup}\lisp} +\def\smalllisp{\begingroup \def\Esmalllisp{\nonfillfinish\endgroup}\lisp} + +% @smallexample and @smalllisp. This is not used unless the @smallbook +% command is given. Originally contributed by Pavel@xerox. +% +\def\smalllispx{\begingroup + \nonfillstart + \let\Esmalllisp = \nonfillfinish + \let\Esmallexample = \nonfillfinish + % + % Smaller fonts for small examples. + \indexfonts \tt + \rawbackslash % make \ output the \ character from the current font (tt) + \gobble +} + +% This is @display; same as @lisp except use roman font. +% +\def\display{\begingroup + \nonfillstart + \let\Edisplay = \nonfillfinish + \gobble +} + +% This is @format; same as @display except don't narrow margins. +% +\def\format{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eformat = \nonfillfinish + \gobble +} + +% @flushleft (same as @format) and @flushright. +% +\def\flushleft{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushleft = \nonfillfinish + \gobble +} +\def\flushright{\begingroup + \let\nonarrowing = t + \nonfillstart + \let\Eflushright = \nonfillfinish + \advance\leftskip by 0pt plus 1fill + \gobble} + +% @quotation does normal linebreaking (hence we can't use \nonfillstart) +% and narrows the margins. +% +\def\quotation{% + \begingroup\inENV %This group ends at the end of the @quotation body + {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip + \singlespace + \parindent=0pt + % We have retained a nonzero parskip for the environment, since we're + % doing normal filling. So to avoid extra space below the environment... + \def\Equotation{\parskip = 0pt \nonfillfinish}% + % + % @cartouche defines \nonarrowing to inhibit narrowing at next level down. + \ifx\nonarrowing\relax + \advance\leftskip by \lispnarrowing + \advance\rightskip by \lispnarrowing + \exdentamount = \lispnarrowing + \let\nonarrowing = \relax + \fi +} + +\message{defuns,} +% Define formatter for defuns +% First, allow user to change definition object font (\df) internally +\def\setdeffont #1 {\csname DEF#1\endcsname} + +\newskip\defbodyindent \defbodyindent=.4in +\newskip\defargsindent \defargsindent=50pt +\newskip\deftypemargin \deftypemargin=12pt +\newskip\deflastargmargin \deflastargmargin=18pt + +\newcount\parencount +% define \functionparens, which makes ( and ) and & do special things. +% \functionparens affects the group it is contained in. +\def\activeparens{% +\catcode`\(=\active \catcode`\)=\active \catcode`\&=\active +\catcode`\[=\active \catcode`\]=\active} + +% Make control sequences which act like normal parenthesis chars. +\let\lparen = ( \let\rparen = ) + +{\activeparens % Now, smart parens don't turn on until &foo (see \amprm) + +% Be sure that we always have a definition for `(', etc. For example, +% if the fn name has parens in it, \boldbrax will not be in effect yet, +% so TeX would otherwise complain about undefined control sequence. +\global\let(=\lparen \global\let)=\rparen +\global\let[=\lbrack \global\let]=\rbrack + +\gdef\functionparens{\boldbrax\let&=\amprm\parencount=0 } +\gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb} +% This is used to turn on special parens +% but make & act ordinary (given that it's active). +\gdef\boldbraxnoamp{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb\let&=\ampnr} + +% Definitions of (, ) and & used in args for functions. +% This is the definition of ( outside of all parentheses. +\gdef\oprm#1 {{\rm\char`\(}#1 \bf \let(=\opnested + \global\advance\parencount by 1 +} +% +% This is the definition of ( when already inside a level of parens. +\gdef\opnested{\char`\(\global\advance\parencount by 1 } +% +\gdef\clrm{% Print a paren in roman if it is taking us back to depth of 0. + % also in that case restore the outer-level definition of (. + \ifnum \parencount=1 {\rm \char `\)}\sl \let(=\oprm \else \char `\) \fi + \global\advance \parencount by -1 } +% If we encounter &foo, then turn on ()-hacking afterwards +\gdef\amprm#1 {{\rm\}\let(=\oprm \let)=\clrm\ } +% +\gdef\normalparens{\boldbrax\let&=\ampnr} +} % End of definition inside \activeparens +%% These parens (in \boldbrax) actually are a little bolder than the +%% contained text. This is especially needed for [ and ] +\def\opnr{{\sf\char`\(}\global\advance\parencount by 1 } +\def\clnr{{\sf\char`\)}\global\advance\parencount by -1 } +\def\ampnr{\&} +\def\lbrb{{\bf\char`\[}} +\def\rbrb{{\bf\char`\]}} + +% First, defname, which formats the header line itself. +% #1 should be the function name. +% #2 should be the type of definition, such as "Function". + +\def\defname #1#2{% +% Get the values of \leftskip and \rightskip as they were +% outside the @def... +\dimen2=\leftskip +\advance\dimen2 by -\defbodyindent +\dimen3=\rightskip +\advance\dimen3 by -\defbodyindent +\noindent % +\setbox0=\hbox{\hskip \deflastargmargin{\rm #2}\hskip \deftypemargin}% +\dimen0=\hsize \advance \dimen0 by -\wd0 % compute size for first line +\dimen1=\hsize \advance \dimen1 by -\defargsindent %size for continuations +\parshape 2 0in \dimen0 \defargsindent \dimen1 % +% Now output arg 2 ("Function" or some such) +% ending at \deftypemargin from the right margin, +% but stuck inside a box of width 0 so it does not interfere with linebreaking +{% Adjust \hsize to exclude the ambient margins, +% so that \rightline will obey them. +\advance \hsize by -\dimen2 \advance \hsize by -\dimen3 +\rlap{\rightline{{\rm #2}\hskip \deftypemargin}}}% +% Make all lines underfull and no complaints: +\tolerance=10000 \hbadness=10000 +\advance\leftskip by -\defbodyindent +\exdentamount=\defbodyindent +{\df #1}\enskip % Generate function name +} + +% Actually process the body of a definition +% #1 should be the terminating control sequence, such as \Edefun. +% #2 should be the "another name" control sequence, such as \defunx. +% #3 should be the control sequence that actually processes the header, +% such as \defunheader. + +\def\defparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\activeparens\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % 61 is `=' +\obeylines\activeparens\spacesplit#3} + +\def\defmethparsebody #1#2#3#4 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 {\begingroup\obeylines\activeparens\spacesplit{#3{##1}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#4}}} + +\def\defopparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\activeparens\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\activeparens\spacesplit{#3{#5}}} + +% These parsing functions are similar to the preceding ones +% except that they do not make parens into active characters. +% These are used for "variables" since they have no arguments. + +\def\defvarparsebody #1#2#3{\begingroup\inENV% Environment for definitionbody +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2{\begingroup\obeylines\spacesplit#3}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup % +\catcode 61=\active % +\obeylines\spacesplit#3} + +% This is used for \def{tp,vr}parsebody. It could probably be used for +% some of the others, too, with some judicious conditionals. +% +\def\parsebodycommon#1#2#3{% + \begingroup\inENV % + \medbreak % + % Define the end token that this defining construct specifies + % so that it will exit this group. + \def#1{\endgraf\endgroup\medbreak}% + \def#2##1 {\begingroup\obeylines\spacesplit{#3{##1}}}% + \parindent=0in + \advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent + \exdentamount=\defbodyindent + \begingroup\obeylines +} + +\def\defvrparsebody#1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{#3{#4}}% +} + +% This loses on `@deftp {Data Type} {struct termios}' -- it thinks the +% type is just `struct', because we lose the braces in `{struct +% termios}' when \spacesplit reads its undelimited argument. Sigh. +% \let\deftpparsebody=\defvrparsebody +% +% So, to get around this, we put \empty in with the type name. That +% way, TeX won't find exactly `{...}' as an undelimited argument, and +% won't strip off the braces. +% +\def\deftpparsebody #1#2#3#4 {% + \parsebodycommon{#1}{#2}{#3}% + \spacesplit{\parsetpheaderline{#3{#4}}}\empty +} + +% Fine, but then we have to eventually remove the \empty *and* the +% braces (if any). That's what this does. +% +\def\removeemptybraces\empty#1\relax{#1} + +% After \spacesplit has done its work, this is called -- #1 is the final +% thing to call, #2 the type name (which starts with \empty), and #3 +% (which might be empty) the arguments. +% +\def\parsetpheaderline#1#2#3{% + #1{\removeemptybraces#2\relax}{#3}% +}% + +\def\defopvarparsebody #1#2#3#4#5 {\begingroup\inENV % +\medbreak % +% Define the end token that this defining construct specifies +% so that it will exit this group. +\def#1{\endgraf\endgroup\medbreak}% +\def#2##1 ##2 {\def#4{##1}% +\begingroup\obeylines\spacesplit{#3{##2}}}% +\parindent=0in +\advance\leftskip by \defbodyindent \advance \rightskip by \defbodyindent +\exdentamount=\defbodyindent +\begingroup\obeylines\spacesplit{#3{#5}}} + +% Split up #2 at the first space token. +% call #1 with two arguments: +% the first is all of #2 before the space token, +% the second is all of #2 after that space token. +% If #2 contains no space token, all of it is passed as the first arg +% and the second is passed as empty. + +{\obeylines +\gdef\spacesplit#1#2^^M{\endgroup\spacesplitfoo{#1}#2 \relax\spacesplitfoo}% +\long\gdef\spacesplitfoo#1#2 #3#4\spacesplitfoo{% +\ifx\relax #3% +#1{#2}{}\else #1{#2}{#3#4}\fi}} + +% So much for the things common to all kinds of definitions. + +% Define @defun. + +% First, define the processing that is wanted for arguments of \defun +% Use this to expand the args and terminate the paragraph they make up + +\def\defunargs #1{\functionparens \sl +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +\hyphenchar\tensl=0 +#1% +\hyphenchar\tensl=45 +\ifnum\parencount=0 \else \errmessage{Unbalanced parentheses in @def}\fi% +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +\def\deftypefunargs #1{% +% Expand, preventing hyphenation at `-' chars. +% Note that groups don't affect changes in \hyphenchar. +% Use \boldbraxnoamp, not \functionparens, so that & is not special. +\boldbraxnoamp +\tclose{#1}% avoid \code because of side effects on active chars +\interlinepenalty=10000 +\advance\rightskip by 0pt plus 1fil +\endgraf\penalty 10000\vskip -\parskip\penalty 10000% +} + +% Do complete processing of one @defun or @defunx line already parsed. + +% @deffn Command forward-char nchars + +\def\deffn{\defmethparsebody\Edeffn\deffnx\deffnheader} + +\def\deffnheader #1#2#3{\doind {fn}{\code{#2}}% +\begingroup\defname {#2}{#1}\defunargs{#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defun == @deffn Function + +\def\defun{\defparsebody\Edefun\defunx\defunheader} + +\def\defunheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Function}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefun int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefun{\defparsebody\Edeftypefun\deftypefunx\deftypefunheader} + +% #1 is the data type. #2 is the name and args. +\def\deftypefunheader #1#2{\deftypefunheaderx{#1}#2 \relax} +% #1 is the data type, #2 the name, #3 the args. +\def\deftypefunheaderx #1#2 #3\relax{% +\doind {fn}{\code{#2}}% Make entry in function index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Function}% +\deftypefunargs {#3}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @deftypefn {Library Function} int foobar (int @var{foo}, float @var{bar}) + +\def\deftypefn{\defmethparsebody\Edeftypefn\deftypefnx\deftypefnheader} + +% \defheaderxcond#1\relax$$$ +% puts #1 in @code, followed by a space, but does nothing if #1 is null. +\def\defheaderxcond#1#2$$${\ifx#1\relax\else\code{#1#2} \fi} + +% #1 is the classification. #2 is the data type. #3 is the name and args. +\def\deftypefnheader #1#2#3{\deftypefnheaderx{#1}{#2}#3 \relax} +% #1 is the classification, #2 the data type, #3 the name, #4 the args. +\def\deftypefnheaderx #1#2#3 #4\relax{% +\doind {fn}{\code{#3}}% Make entry in function index +\begingroup +\normalparens % notably, turn off `&' magic, which prevents +% at least some C++ text from working +\defname {\defheaderxcond#2\relax$$$#3}{#1}% +\deftypefunargs {#4}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defmac == @deffn Macro + +\def\defmac{\defparsebody\Edefmac\defmacx\defmacheader} + +\def\defmacheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Macro}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% @defspec == @deffn Special Form + +\def\defspec{\defparsebody\Edefspec\defspecx\defspecheader} + +\def\defspecheader #1#2{\doind {fn}{\code{#1}}% Make entry in function index +\begingroup\defname {#1}{Special Form}% +\defunargs {#2}\endgroup % +\catcode 61=\other % Turn off change made in \defparsebody +} + +% This definition is run if you use @defunx +% anywhere other than immediately after a @defun or @defunx. + +\def\deffnx #1 {\errmessage{@deffnx in invalid context}} +\def\defunx #1 {\errmessage{@defunx in invalid context}} +\def\defmacx #1 {\errmessage{@defmacx in invalid context}} +\def\defspecx #1 {\errmessage{@defspecx in invalid context}} +\def\deftypefnx #1 {\errmessage{@deftypefnx in invalid context}} +\def\deftypemethodx #1 {\errmessage{@deftypemethodx in invalid context}} +\def\deftypeunx #1 {\errmessage{@deftypeunx in invalid context}} + +% @defmethod, and so on + +% @defop {Funny Method} foo-class frobnicate argument + +\def\defop #1 {\def\defoptype{#1}% +\defopparsebody\Edefop\defopx\defopheader\defoptype} + +\def\defopheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% Make entry in function index +\begingroup\defname {#2}{\defoptype{} on #1}% +\defunargs {#3}\endgroup % +} + +% @deftypemethod foo-class return-type foo-method args +% +\def\deftypemethod{% + \defmethparsebody\Edeftypemethod\deftypemethodx\deftypemethodheader} +% +% #1 is the class name, #2 the data type, #3 the method name, #4 the args. +\def\deftypemethodheader#1#2#3#4{% + \deftypefnheaderx{Method on #1}{#2}#3 #4\relax +} + +% @defmethod == @defop Method + +\def\defmethod{\defmethparsebody\Edefmethod\defmethodx\defmethodheader} + +\def\defmethodheader #1#2#3{% +\dosubind {fn}{\code{#2}}{on #1}% entry in function index +\begingroup\defname {#2}{Method on #1}% +\defunargs {#3}\endgroup % +} + +% @defcv {Class Option} foo-class foo-flag + +\def\defcv #1 {\def\defcvtype{#1}% +\defopvarparsebody\Edefcv\defcvx\defcvarheader\defcvtype} + +\def\defcvarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{\defcvtype{} of #1}% +\defvarargs {#3}\endgroup % +} + +% @defivar == @defcv {Instance Variable} + +\def\defivar{\defvrparsebody\Edefivar\defivarx\defivarheader} + +\def\defivarheader #1#2#3{% +\dosubind {vr}{\code{#2}}{of #1}% Make entry in var index +\begingroup\defname {#2}{Instance Variable of #1}% +\defvarargs {#3}\endgroup % +} + +% These definitions are run if you use @defmethodx, etc., +% anywhere other than immediately after a @defmethod, etc. + +\def\defopx #1 {\errmessage{@defopx in invalid context}} +\def\defmethodx #1 {\errmessage{@defmethodx in invalid context}} +\def\defcvx #1 {\errmessage{@defcvx in invalid context}} +\def\defivarx #1 {\errmessage{@defivarx in invalid context}} + +% Now @defvar + +% First, define the processing that is wanted for arguments of @defvar. +% This is actually simple: just print them in roman. +% This must expand the args and terminate the paragraph they make up +\def\defvarargs #1{\normalparens #1% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000} + +% @defvr Counter foo-count + +\def\defvr{\defvrparsebody\Edefvr\defvrx\defvrheader} + +\def\defvrheader #1#2#3{\doind {vr}{\code{#2}}% +\begingroup\defname {#2}{#1}\defvarargs{#3}\endgroup} + +% @defvar == @defvr Variable + +\def\defvar{\defvarparsebody\Edefvar\defvarx\defvarheader} + +\def\defvarheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{Variable}% +\defvarargs {#2}\endgroup % +} + +% @defopt == @defvr {User Option} + +\def\defopt{\defvarparsebody\Edefopt\defoptx\defoptheader} + +\def\defoptheader #1#2{\doind {vr}{\code{#1}}% Make entry in var index +\begingroup\defname {#1}{User Option}% +\defvarargs {#2}\endgroup % +} + +% @deftypevar int foobar + +\def\deftypevar{\defvarparsebody\Edeftypevar\deftypevarx\deftypevarheader} + +% #1 is the data type. #2 is the name, perhaps followed by text that +% is actually part of the data type, which should not be put into the index. +\def\deftypevarheader #1#2{% +\dovarind#2 \relax% Make entry in variables index +\begingroup\defname {\defheaderxcond#1\relax$$$#2}{Variable}% +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} +\def\dovarind#1 #2\relax{\doind{vr}{\code{#1}}} + +% @deftypevr {Global Flag} int enable + +\def\deftypevr{\defvrparsebody\Edeftypevr\deftypevrx\deftypevrheader} + +\def\deftypevrheader #1#2#3{\dovarind#3 \relax% +\begingroup\defname {\defheaderxcond#2\relax$$$#3}{#1} +\interlinepenalty=10000 +\endgraf\penalty 10000\vskip -\parskip\penalty 10000 +\endgroup} + +% This definition is run if you use @defvarx +% anywhere other than immediately after a @defvar or @defvarx. + +\def\defvrx #1 {\errmessage{@defvrx in invalid context}} +\def\defvarx #1 {\errmessage{@defvarx in invalid context}} +\def\defoptx #1 {\errmessage{@defoptx in invalid context}} +\def\deftypevarx #1 {\errmessage{@deftypevarx in invalid context}} +\def\deftypevrx #1 {\errmessage{@deftypevrx in invalid context}} + +% Now define @deftp +% Args are printed in bold, a slight difference from @defvar. + +\def\deftpargs #1{\bf \defvarargs{#1}} + +% @deftp Class window height width ... + +\def\deftp{\deftpparsebody\Edeftp\deftpx\deftpheader} + +\def\deftpheader #1#2#3{\doind {tp}{\code{#2}}% +\begingroup\defname {#2}{#1}\deftpargs{#3}\endgroup} + +% This definition is run if you use @deftpx, etc +% anywhere other than immediately after a @deftp, etc. + +\def\deftpx #1 {\errmessage{@deftpx in invalid context}} + + +\message{cross reference,} +% Define cross-reference macros +\newwrite \auxfile + +\newif\ifhavexrefs % True if xref values are known. +\newif\ifwarnedxrefs % True if we warned once that they aren't known. + +% @inforef is simple. +\def\inforef #1{\inforefzzz #1,,,,**} +\def\inforefzzz #1,#2,#3,#4**{\putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}}, + node \samp{\ignorespaces#1{}}} + +% \setref{foo} defines a cross-reference point named foo. + +\def\setref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ysectionnumberandtype}} + +\def\unnumbsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Ynothing}} + +\def\appendixsetref#1{% +\dosetq{#1-title}{Ytitle}% +\dosetq{#1-pg}{Ypagenumber}% +\dosetq{#1-snt}{Yappendixletterandtype}} + +% \xref, \pxref, and \ref generate cross-references to specified points. +% For \xrefX, #1 is the node name, #2 the name of the Info +% cross-reference, #3 the printed node name, #4 the name of the Info +% file, #5 the name of the printed manual. All but the node name can be +% omitted. +% +\def\pxref#1{\putwordsee{} \xrefX[#1,,,,,,,]} +\def\xref#1{\putwordSee{} \xrefX[#1,,,,,,,]} +\def\ref#1{\xrefX[#1,,,,,,,]} +\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup + \def\printedmanual{\ignorespaces #5}% + \def\printednodename{\ignorespaces #3}% + \setbox1=\hbox{\printedmanual}% + \setbox0=\hbox{\printednodename}% + \ifdim \wd0 = 0pt + % No printed node name was explicitly given. + \expandafter\ifx\csname SETxref-automatic-section-title\endcsname\relax + % Use the node name inside the square brackets. + \def\printednodename{\ignorespaces #1}% + \else + % Use the actual chapter/section title appear inside + % the square brackets. Use the real section title if we have it. + \ifdim \wd1>0pt% + % It is in another manual, so we don't have it. + \def\printednodename{\ignorespaces #1}% + \else + \ifhavexrefs + % We know the real title if we have the xref values. + \def\printednodename{\refx{#1-title}{}}% + \else + % Otherwise just copy the Info node name. + \def\printednodename{\ignorespaces #1}% + \fi% + \fi + \fi + \fi + % + % If we use \unhbox0 and \unhbox1 to print the node names, TeX does not + % insert empty discretionaries after hyphens, which means that it will + % not find a line break at a hyphen in a node names. Since some manuals + % are best written with fairly long node names, containing hyphens, this + % is a loss. Therefore, we give the text of the node name again, so it + % is as if TeX is seeing it for the first time. + \ifdim \wd1 > 0pt + \putwordsection{} ``\printednodename'' in \cite{\printedmanual}% + \else + % _ (for example) has to be the character _ for the purposes of the + % control sequence corresponding to the node, but it has to expand + % into the usual \leavevmode...\vrule stuff for purposes of + % printing. So we \turnoffactive for the \refx-snt, back on for the + % printing, back off for the \refx-pg. + {\turnoffactive \refx{#1-snt}{}}% + \space [\printednodename],\space + \turnoffactive \putwordpage\tie\refx{#1-pg}{}% + \fi +\endgroup} + +% \dosetq is the interface for calls from other macros + +% Use \turnoffactive so that punctuation chars such as underscore +% work in node names. +\def\dosetq #1#2{{\let\folio=0 \turnoffactive +\edef\next{\write\auxfile{\internalsetq {#1}{#2}}}% +\next}} + +% \internalsetq {foo}{page} expands into +% CHARACTERS 'xrdef {foo}{...expansion of \Ypage...} +% When the aux file is read, ' is the escape character + +\def\internalsetq #1#2{'xrdef {#1}{\csname #2\endcsname}} + +% Things to be expanded by \internalsetq + +\def\Ypagenumber{\folio} + +\def\Ytitle{\thissection} + +\def\Ynothing{} + +\def\Ysectionnumberandtype{% +\ifnum\secno=0 \putwordChapter\xreftie\the\chapno % +\else \ifnum \subsecno=0 \putwordSection\xreftie\the\chapno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\def\Yappendixletterandtype{% +\ifnum\secno=0 \putwordAppendix\xreftie'char\the\appendixno{}% +\else \ifnum \subsecno=0 \putwordSection\xreftie'char\the\appendixno.\the\secno % +\else \ifnum \subsubsecno=0 % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno % +\else % +\putwordSection\xreftie'char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno % +\fi \fi \fi } + +\gdef\xreftie{'tie} + +% Use TeX 3.0's \inputlineno to get the line number, for better error +% messages, but if we're using an old version of TeX, don't do anything. +% +\ifx\inputlineno\thisisundefined + \let\linenumber = \empty % Non-3.0. +\else + \def\linenumber{\the\inputlineno:\space} +\fi + +% Define \refx{NAME}{SUFFIX} to reference a cross-reference string named NAME. +% If its value is nonempty, SUFFIX is output afterward. + +\def\refx#1#2{% + \expandafter\ifx\csname X#1\endcsname\relax + % If not defined, say something at least. + $\langle$un\-de\-fined$\rangle$% + \ifhavexrefs + \message{\linenumber Undefined cross reference `#1'.}% + \else + \ifwarnedxrefs\else + \global\warnedxrefstrue + \message{Cross reference values unknown; you must run TeX again.}% + \fi + \fi + \else + % It's defined, so just use it. + \csname X#1\endcsname + \fi + #2% Output the suffix in any case. +} + +% This is the macro invoked by entries in the aux file. +\def\xrdef #1#2{{% + \catcode`\'=\other + \expandafter\gdef\csname X#1\endcsname{#2}% +}} + +% Read the last existing aux file, if any. No error if none exists. +\def\readauxfile{\begingroup + \catcode`\^^@=\other + \catcode`\^^A=\other + \catcode`\^^B=\other + \catcode`\^^C=\other + \catcode`\^^D=\other + \catcode`\^^E=\other + \catcode`\^^F=\other + \catcode`\^^G=\other + \catcode`\^^H=\other + \catcode`\^^K=\other + \catcode`\^^L=\other + \catcode`\^^N=\other + \catcode`\^^P=\other + \catcode`\^^Q=\other + \catcode`\^^R=\other + \catcode`\^^S=\other + \catcode`\^^T=\other + \catcode`\^^U=\other + \catcode`\^^V=\other + \catcode`\^^W=\other + \catcode`\^^X=\other + \catcode`\^^Z=\other + \catcode`\^^[=\other + \catcode`\^^\=\other + \catcode`\^^]=\other + \catcode`\^^^=\other + \catcode`\^^_=\other + \catcode`\@=\other + \catcode`\^=\other + % It was suggested to define this as 7, which would allow ^^e4 etc. + % in xref tags, i.e., node names. But since ^^e4 notation isn't + % supported in the main text, it doesn't seem desirable. Furthermore, + % that is not enough: for node names that actually contain a ^ + % character, we would end up writing a line like this: 'xrdef {'hat + % b-title}{'hat b} and \xrdef does a \csname...\endcsname on the first + % argument, and \hat is not an expandable control sequence. It could + % all be worked out, but why? Either we support ^^ or we don't. + % + % The other change necessary for this was to define \auxhat: + % \def\auxhat{\def^{'hat }}% extra space so ok if followed by letter + % and then to call \auxhat in \setq. + % + \catcode`\~=\other + \catcode`\[=\other + \catcode`\]=\other + \catcode`\"=\other + \catcode`\_=\other + \catcode`\|=\other + \catcode`\<=\other + \catcode`\>=\other + \catcode`\$=\other + \catcode`\#=\other + \catcode`\&=\other + % `\+ does not work, so use 43. + \catcode43=\other + % Make the characters 128-255 be printing characters + {% + \count 1=128 + \def\loop{% + \catcode\count 1=\other + \advance\count 1 by 1 + \ifnum \count 1<256 \loop \fi + }% + }% + % The aux file uses ' as the escape (for now). + % Turn off \ as an escape so we do not lose on + % entries which were dumped with control sequences in their names. + % For example, 'xrdef {$\leq $-fun}{page ...} made by @defun ^^ + % Reference to such entries still does not work the way one would wish, + % but at least they do not bomb out when the aux file is read in. + \catcode`\{=1 + \catcode`\}=2 + \catcode`\%=\other + \catcode`\'=0 + \catcode`\\=\other + % + \openin 1 \jobname.aux + \ifeof 1 \else + \closein 1 + \input \jobname.aux + \global\havexrefstrue + \global\warnedobstrue + \fi + % Open the new aux file. TeX will close it automatically at exit. + \openout\auxfile=\jobname.aux +\endgroup} + + +% Footnotes. + +\newcount \footnoteno + +% The trailing space in the following definition for supereject is +% vital for proper filling; pages come out unaligned when you do a +% pagealignmacro call if that space before the closing brace is +% removed. (Generally, numeric constants should always be followed by a +% space to prevent strange expansion errors.) +\def\supereject{\par\penalty -20000\footnoteno =0 } + +% @footnotestyle is meaningful for info output only. +\let\footnotestyle=\comment + +\let\ptexfootnote=\footnote + +{\catcode `\@=11 +% +% Auto-number footnotes. Otherwise like plain. +\gdef\footnote{% + \global\advance\footnoteno by \@ne + \edef\thisfootno{$^{\the\footnoteno}$}% + % + % In case the footnote comes at the end of a sentence, preserve the + % extra spacing after we do the footnote number. + \let\@sf\empty + \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\/\fi + % + % Remove inadvertent blank space before typesetting the footnote number. + \unskip + \thisfootno\@sf + \footnotezzz +}% + +% Don't bother with the trickery in plain.tex to not require the +% footnote text as a parameter. Our footnotes don't need to be so general. +% +% Oh yes, they do; otherwise, @ifset and anything else that uses +% \parseargline fail inside footnotes because the tokens are fixed when +% the footnote is read. --karl, 16nov96. +% +\long\gdef\footnotezzz{\insert\footins\bgroup + % We want to typeset this text as a normal paragraph, even if the + % footnote reference occurs in (for example) a display environment. + % So reset some parameters. + \interlinepenalty\interfootnotelinepenalty + \splittopskip\ht\strutbox % top baseline for broken footnotes + \splitmaxdepth\dp\strutbox + \floatingpenalty\@MM + \leftskip\z@skip + \rightskip\z@skip + \spaceskip\z@skip + \xspaceskip\z@skip + \parindent\defaultparindent + % + % Hang the footnote text off the number. + \hang + \textindent{\thisfootno}% + % + % Don't crash into the line above the footnote text. Since this + % expands into a box, it must come within the paragraph, lest it + % provide a place where TeX can split the footnote. + \footstrut + \futurelet\next\fo@t +} +\def\fo@t{\ifcat\bgroup\noexpand\next \let\next\f@@t + \else\let\next\f@t\fi \next} +\def\f@@t{\bgroup\aftergroup\@foot\let\next} +\def\f@t#1{#1\@foot} +\def\@foot{\strut\egroup} + +}%end \catcode `\@=11 + +% Set the baselineskip to #1, and the lineskip and strut size +% correspondingly. There is no deep meaning behind these magic numbers +% used as factors; they just match (closely enough) what Knuth defined. +% +\def\lineskipfactor{.08333} +\def\strutheightpercent{.70833} +\def\strutdepthpercent {.29167} +% +\def\setleading#1{% + \normalbaselineskip = #1\relax + \normallineskip = \lineskipfactor\normalbaselineskip + \normalbaselines + \setbox\strutbox =\hbox{% + \vrule width0pt height\strutheightpercent\baselineskip + depth \strutdepthpercent \baselineskip + }% +} + +% @| inserts a changebar to the left of the current line. It should +% surround any changed text. This approach does *not* work if the +% change spans more than two lines of output. To handle that, we would +% have adopt a much more difficult approach (putting marks into the main +% vertical list for the beginning and end of each change). +% +\def\|{% + % \vadjust can only be used in horizontal mode. + \leavevmode + % + % Append this vertical mode material after the current line in the output. + \vadjust{% + % We want to insert a rule with the height and depth of the current + % leading; that is exactly what \strutbox is supposed to record. + \vskip-\baselineskip + % + % \vadjust-items are inserted at the left edge of the type. So + % the \llap here moves out into the left-hand margin. + \llap{% + % + % For a thicker or thinner bar, change the `1pt'. + \vrule height\baselineskip width1pt + % + % This is the space between the bar and the text. + \hskip 12pt + }% + }% +} + +% For a final copy, take out the rectangles +% that mark overfull boxes (in case you have decided +% that the text looks ok even though it passes the margin). +% +\def\finalout{\overfullrule=0pt} + +% @image. We use the macros from epsf.tex to support this. +% If epsf.tex is not installed and @image is used, we complain. +% +% Check for and read epsf.tex up front. If we read it only at @image +% time, we might be inside a group, and then its definitions would get +% undone and the next image would fail. +\openin 1 = xepsf.tex +\ifeof 1 \else + \closein 1 + \def\epsfannounce{\toks0 = }% do not bother showing banner + \input epsf.tex +\fi +% +\newif\ifwarnednoepsf +\newhelp\noepsfhelp{epsf.tex must be installed for images to + work. It is also included in the Texinfo distribution, or you can get + it from ftp://ftp.tug.org/tex/epsf.tex.} +% +% Only complain once about lack of epsf.tex. +\def\image#1{% + \ifx\epsfbox\undefined + \ifwarnednoepsf \else + \errhelp = \noepsfhelp + \errmessage{epsf.tex not found, images will be ignored}% + \global\warnednoepsftrue + \fi + \else + \imagexxx #1,,,\finish + \fi +} +% +% Arguments to @image: +% #1 is (mandatory) image filename; we tack on .eps extension. +% #2 is (optional) width, #3 is (optional) height. +% #4 is just the usual extra ignored arg for parsing this stuff. +\def\imagexxx#1,#2,#3,#4\finish{% + % \epsfbox itself resets \epsf?size at each figure. + \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi + \setbox0 = \hbox{\ignorespaces #3}\ifdim\wd0 > 0pt \epsfysize=#3\relax \fi + \epsfbox{#1.eps}% +} + +% End of control word definitions. + + +\message{and turning on texinfo input format.} + +\def\openindices{% + \newindex{cp}% + \newcodeindex{fn}% + \newcodeindex{vr}% + \newcodeindex{tp}% + \newcodeindex{ky}% + \newcodeindex{pg}% +} + +% Set some numeric style parameters, for 8.5 x 11 format. + +\hsize = 6in +\hoffset = .25in +\newdimen\defaultparindent \defaultparindent = 15pt +\parindent = \defaultparindent +\parskip 3pt plus 2pt minus 1pt +\setleading{13.2pt} +\advance\topskip by 1.2cm + +\chapheadingskip = 15pt plus 4pt minus 2pt +\secheadingskip = 12pt plus 3pt minus 2pt +\subsecheadingskip = 9pt plus 2pt minus 2pt + +% Prevent underfull vbox error messages. +\vbadness=10000 + +% Following George Bush, just get rid of widows and orphans. +\widowpenalty=10000 +\clubpenalty=10000 + +% Use TeX 3.0's \emergencystretch to help line breaking, but if we're +% using an old version of TeX, don't do anything. We want the amount of +% stretch added to depend on the line length, hence the dependence on +% \hsize. This makes it come to about 9pt for the 8.5x11 format. +% +\ifx\emergencystretch\thisisundefined + % Allow us to assign to \emergencystretch anyway. + \def\emergencystretch{\dimen0}% +\else + \emergencystretch = \hsize + \divide\emergencystretch by 45 +\fi + +% Use @smallbook to reset parameters for 7x9.5 format (or else 7x9.25) +\def\smallbook{ + \global\chapheadingskip = 15pt plus 4pt minus 2pt + \global\secheadingskip = 12pt plus 3pt minus 2pt + \global\subsecheadingskip = 9pt plus 2pt minus 2pt + % + \global\lispnarrowing = 0.3in + \setleading{12pt} + \advance\topskip by -1cm + \global\parskip 2pt plus 1pt + \global\hsize = 5in + \global\vsize=7.5in + \global\tolerance=700 + \global\hfuzz=1pt + \global\contentsrightmargin=0pt + \global\deftypemargin=0pt + \global\defbodyindent=.5cm + % + \global\pagewidth=\hsize + \global\pageheight=\vsize + % + \global\let\smalllisp=\smalllispx + \global\let\smallexample=\smalllispx + \global\def\Esmallexample{\Esmalllisp} +} + +% Use @afourpaper to print on European A4 paper. +\def\afourpaper{ +\global\tolerance=700 +\global\hfuzz=1pt +\setleading{12pt} +\global\parskip 15pt plus 1pt + +\global\vsize= 53\baselineskip +\advance\vsize by \topskip +%\global\hsize= 5.85in % A4 wide 10pt +\global\hsize= 6.5in +\global\outerhsize=\hsize +\global\advance\outerhsize by 0.5in +\global\outervsize=\vsize +\global\advance\outervsize by 0.6in + +\global\pagewidth=\hsize +\global\pageheight=\vsize +} + +\bindingoffset=0pt +\normaloffset=\hoffset +\pagewidth=\hsize +\pageheight=\vsize + +% Allow control of the text dimensions. Parameters in order: textheight; +% textwidth; voffset; hoffset; binding offset; topskip. +% All require a dimension; +% header is additional; added length extends the bottom of the page. + +\def\changepagesizes#1#2#3#4#5#6{ + \global\vsize= #1 + \global\topskip= #6 + \advance\vsize by \topskip + \global\voffset= #3 + \global\hsize= #2 + \global\outerhsize=\hsize + \global\advance\outerhsize by 0.5in + \global\outervsize=\vsize + \global\advance\outervsize by 0.6in + \global\pagewidth=\hsize + \global\pageheight=\vsize + \global\normaloffset= #4 + \global\bindingoffset= #5} + +% A specific text layout, 24x15cm overall, intended for A4 paper. Top margin +% 29mm, hence bottom margin 28mm, nominal side margin 3cm. +\def\afourlatex + {\global\tolerance=700 + \global\hfuzz=1pt + \setleading{12pt} + \global\parskip 15pt plus 1pt + \advance\baselineskip by 1.6pt + \changepagesizes{237mm}{150mm}{3.6mm}{3.6mm}{3mm}{7mm} + } + +% Use @afourwide to print on European A4 paper in wide format. +\def\afourwide{\afourpaper +\changepagesizes{9.5in}{6.5in}{\hoffset}{\normaloffset}{\bindingoffset}{7mm}} + +% Define macros to output various characters with catcode for normal text. +\catcode`\"=\other +\catcode`\~=\other +\catcode`\^=\other +\catcode`\_=\other +\catcode`\|=\other +\catcode`\<=\other +\catcode`\>=\other +\catcode`\+=\other +\def\normaldoublequote{"} +\def\normaltilde{~} +\def\normalcaret{^} +\def\normalunderscore{_} +\def\normalverticalbar{|} +\def\normalless{<} +\def\normalgreater{>} +\def\normalplus{+} + +% This macro is used to make a character print one way in ttfont +% where it can probably just be output, and another way in other fonts, +% where something hairier probably needs to be done. +% +% #1 is what to print if we are indeed using \tt; #2 is what to print +% otherwise. Since all the Computer Modern typewriter fonts have zero +% interword stretch (and shrink), and it is reasonable to expect all +% typewriter fonts to have this, we can check that font parameter. +% +\def\ifusingtt#1#2{\ifdim \fontdimen3\the\font=0pt #1\else #2\fi} + +% Turn off all special characters except @ +% (and those which the user can use as if they were ordinary). +% Most of these we simply print from the \tt font, but for some, we can +% use math or other variants that look better in normal text. + +\catcode`\"=\active +\def\activedoublequote{{\tt \char '042}} +\let"=\activedoublequote +\catcode`\~=\active +\def~{{\tt \char '176}} +\chardef\hat=`\^ +\catcode`\^=\active +\def^{{\tt \hat}} + +\catcode`\_=\active +\def_{\ifusingtt\normalunderscore\_} +% Subroutine for the previous macro. +\def\_{\leavevmode \kern.06em \vbox{\hrule width.3em height.1ex}} + +\catcode`\|=\active +\def|{{\tt \char '174}} +\chardef \less=`\< +\catcode`\<=\active +\def<{{\tt \less}} +\chardef \gtr=`\> +\catcode`\>=\active +\def>{{\tt \gtr}} +\catcode`\+=\active +\def+{{\tt \char 43}} +%\catcode 27=\active +%\def^^[{$\diamondsuit$} + +% Set up an active definition for =, but don't enable it most of the time. +{\catcode`\==\active +\global\def={{\tt \char 61}}} + +\catcode`+=\active +\catcode`\_=\active + +% If a .fmt file is being used, characters that might appear in a file +% name cannot be active until we have parsed the command line. +% So turn them off again, and have \everyjob (or @setfilename) turn them on. +% \otherifyactive is called near the end of this file. +\def\otherifyactive{\catcode`+=\other \catcode`\_=\other} + +\catcode`\@=0 + +% \rawbackslashxx output one backslash character in current font +\global\chardef\rawbackslashxx=`\\ +%{\catcode`\\=\other +%@gdef@rawbackslashxx{\}} + +% \rawbackslash redefines \ as input to do \rawbackslashxx. +{\catcode`\\=\active +@gdef@rawbackslash{@let\=@rawbackslashxx }} + +% \normalbackslash outputs one backslash in fixed width font. +\def\normalbackslash{{\tt\rawbackslashxx}} + +% Say @foo, not \foo, in error messages. +\escapechar=`\@ + +% \catcode 17=0 % Define control-q +\catcode`\\=\active + +% Used sometimes to turn off (effectively) the active characters +% even after parsing them. +@def@turnoffactive{@let"=@normaldoublequote +@let\=@realbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +@def@normalturnoffactive{@let"=@normaldoublequote +@let\=@normalbackslash +@let~=@normaltilde +@let^=@normalcaret +@let_=@normalunderscore +@let|=@normalverticalbar +@let<=@normalless +@let>=@normalgreater +@let+=@normalplus} + +% Make _ and + \other characters, temporarily. +% This is canceled by @fixbackslash. +@otherifyactive + +% If a .fmt file is being used, we don't want the `\input texinfo' to show up. +% That is what \eatinput is for; after that, the `\' should revert to printing +% a backslash. +% +@gdef@eatinput input texinfo{@fixbackslash} +@global@let\ = @eatinput + +% On the other hand, perhaps the file did not have a `\input texinfo'. Then +% the first `\{ in the file would cause an error. This macro tries to fix +% that, assuming it is called before the first `\' could plausibly occur. +% Also back turn on active characters that might appear in the input +% file name, in case not using a pre-dumped format. +% +@gdef@fixbackslash{@ifx\@eatinput @let\ = @normalbackslash @fi + @catcode`+=@active @catcode`@_=@active} + +%% These look ok in all fonts, so just make them not special. The @rm below +%% makes sure that the current font starts out as the newly loaded cmr10 +@catcode`@$=@other @catcode`@%=@other @catcode`@&=@other @catcode`@#=@other + +@textfonts +@rm + +@c Local variables: +@c page-delimiter: "^\\\\message" +@c End: diff --git a/contrib/amd/doc/version.texi b/contrib/amd/doc/version.texi new file mode 100644 index 0000000..225ecdb --- /dev/null +++ b/contrib/amd/doc/version.texi @@ -0,0 +1,3 @@ +@set UPDATED 22 April 1998 +@set EDITION 6.0a16 +@set VERSION 6.0a16 |