An automounter allows the binding of a directory name to a filesystm to be delayed until the name is referenced. This can be advantageous merely to reduce the number of simultaneous mounts, but it can improve system reliability, simplify administration and provide transparent redundancy as well. Examples of automouters are autofs (supplied with Linux) and automountd (supplied with SUNOS) Amd is an advanced automounter, with great flexibility. It is the default automounter pre-installed in FreeBSD and is currently maintained for over 100 operating systems by Erez Zadok. As of the fall of 2000, it is at version 6.04.
As root in FreeBSD, you can start Amd with just:
where Amd will wait for requests to use directories in
the automount point (/net
) and mount the appropriate
filesystems described in the mount map
(/etc/disk.map
). That is, once Amd is running, a file
open requesting /net/foo
will result in Amd searching
/etc/disk.map
for the foo
entry, and following
the instructions there for mounting a (possibly remote) filesystem in
/net/foo
to satisfy the request.
The remote filesystem is not actually mounted in the /net
directory, rather it is mounted in a temporary mount directory
(/a
by default) and symbolic link is created that points from
the net directory to the temporary mount point. Think of /net
as the logical mount point and /a
as the real mount point.
[Question: Why is /net not specified in the map file? How do you spread
mounts across several watched directories?]
The enormous power of Amd comes from the embedded macro language
supported in the map file, which allows the mount specification to be
created from a list of possible matches according to the properties of the
request. This language is discussed below in a series of examples that are
not intended to be realistic, but will show the flexibility of the mapping
translation that can be obtained. The reference manual has more realistic
(and more complicated) examples.
In a real installation, the startup script might include a large number of
options and other parameters. Such a script wants to know the process id
(-p
) and set the logfile location (-l
). It may
want to change the length of time that a filesystem remains mounted after
last use (-c
and -w
) or the location of the real
mount points (-a
). If there are many options, you may wish to
include them in an amd.conf file (-F), but that is beyond the scope
of this introduction and you are referred to the man page for details.
While experimenting with Amd at a console, a convenient command line is:
which will log all actions to the console as they occur. You probably want to open up another console for testing.
where key
is the name of a subdirectory in the automount
point (/net
in our example) and value
is a space
delimited list of possible locations. Here is an example with two keys and
a single location for each:
With this map Amd will mount fileserver:/joe
or
fileserver:/may
as required when either directory in
/net
is opened. The value of rfs
is the left
hand side of an NFS export specification on the machine with the
canonical name given by the value of rhost
. It is possible
to allow CNAMEs in the specification via an option.
Of course, on a large system, there will be many users, and the map file would be both large and a nuisance to maintain. Amd allows common elements to be specified in a defaults line:
Probably Joe and May share a single filesystem on the fileserver, perhaps
subdirectories of the /home
exported filesystem. In which
case the map would be:
The sublink
shows where in the remote filesystem the logical
link in /net
should point. Somewhat more surprisingly, the
key can be a regular expression:
will match every possible key and map it to the appropriate
directory on the same remote fileserver. That is /net/joe
becomes a link to /a/fileserver/home/joe
, and Amd
arranges to mount the remote filesystem as required. Note how
${key} expands to the actual value of the key at time
/net/key
is requested. If there is no appropriately named
export from fileserver
then the user will get a permission
denied message. Or try:
if you need to spread the home directories over two fileservers according to the first letter of the login name. [Note: this sort of regular expression doesn't seem to be recognized in our case.] This works to reduce the size of maps on clients systems, but another problem is the proliferation of slightly different maps for different systems. For example, if you tried to use the above map on fileserver itself, Amd would try to nfs mount its own export, and that is disallowed. So Amd allows selectors to provide alternative definitions so that a single map file may server many machines. For example:
uses the first location on client machines (host!=fileserver) and the
second when executed on the fileserver itself. The alternate locations may
be local or remote, and Amd will pick the first that has a valid
selector. Here fs
points to the physical data when
type:=link
, while for other link-types, fs
designates the place for Amd to mount remote filesystems.
[Question: What does || do?]There are several mount types, including
ufs, allowing Amd to connect the key to any possible
directory in the network.
Note the syntax: the backslash keeps the key-value pair on a single logical line, while spaces delimit the alternative locations and the key.
The selection can be based on any of a large number of criteria, including OS name, netgroup, big or little endedness, etc. These are host machine characteristics, and their values can always (and only) obtained by running:
Alternate NFS and Link specifications are so common that Amd has a special combination type given by nfsl:
Regardless of the OS, the client map is the same, but it depends on the
call to Amd to supply the value of ${os} . On our machine
${os} evaluates to freebsd3
, so to use this feature we
would need to create a directory /utils/freebsd3
on
fileserver. Again, the exact result of expanding any of the macro
variables can be learned from the -v
option on the
amd
command. When we add a Linux version, we will need to add
a directory /utils/linux2
on the same fileserver. The real
directories are likely to be on different systems, in which case the map
could be written as:
/bin/utils
directories were kept. Most of the macro values can be overridden on the Amd command line, if the supplied values are insufficiently specific for your application. Again, see the man page for details.
The selection of opts that can be specified in any location is much the same as for the mount command, with a few extra noted in the reference manual. [Question: What does - do?]
Watch the log file carefully if Amd doesn't seem to be doing what
you expect. It will report what it tried to mount where, and that may
suggest what you may have done wrong. Also watch /a
for
mounted remote filesystems. The Amq program will return the status
of automounted filesystems. Try:
for mount status listed by automount points, by physical mount points, or print statistics for a named automount point. Amq can also control the daemon:
will cause Amd to reread the map files or cause an unmount of the logical directory named.[Note: On our system this has has no apparent effect.] You can also cause Amd to reread the map files with:
In the reference manual you can learn how to use NIS, ndbm, LDAP and other techniques to distribute the maps, reference replicated filesystems for redundancy, distribute mail to user's home directories, automount other types of filesystems such as floppies and CD-ROMs, match complex keys with automounted directories in other automounted directories, use the many other macro variables and even specify the program and arguments Amd should execute when requests to open (or close) directories occur.
Amd uses a different map format than Autofs, so you can't share maps (via NIS, for example) with other automounters which use the traditional SUN format, unless you are as clever as the author of the letter attached at the end of this note.
The Am-Utils home page is located http://www.am-utils.org. There you will find complete source code, many binaries and a 122 page reference manual. But don't go looking for the values of the macro variables - you get them by running the program.
Since this tutorial was first written, Erez Zadok has written a book Linux NFS and Automounter Administration which can serve as both a reference manual and a comprehensive introduction to Amd, even for FreeBSD.
Daniel Feenberg
Mohan Ramanajan
Last Modified
1 March 2002
Current version kept at:
http://www.nber.org/amd.html
A potential Amd user posted a note asking where to find out about it. This was one response.
From hag@linnaean.org Mon Nov 20 12:54:26 2000 Date: Mon, 20 Nov 2000 12:32:01 -0500 From: Daniel HagertyTo: Daniel Feenberg Cc: Doug Mildram , bblisa@bblisa.org Subject: Re: BBLISA: "amd" on freeBSD for automount with NIS ? > In short - Amd uses a different map sytax from autofs, and using it on an > NIS client to a Solaris server is an advanced application. We would be > interested in hearing from anyone who is doing that. I know a place that does this; automagically no less. The maps are maintained in solaris automount format, and there's an awk script that generates amd format maps from these. The (somewhat illegible) conversion script is appended. YMMV, depending on the complexity of your solaris automount maps. But this is known to work in one place... The typical amd startup is something like amd `ypcat -k amd.master` . # # translate simple automount map into equivalent amd map. # BEGIN { print "#"; print "# PLEASE! Don't edit this file directly!"; print "# Canonical version of this map is in " ARGV[1]; print "# Please edit that file to make changes, then:"; print "# cd /var/yp ; make"; print "#"; print "/defaults\topts:=rw,grpid,intr,rsize=8192,wsize=8192,resvport;type:=nfs"; } { key = $1; if (NF == 0) next; if (NF > 2) { gsub(/^-/, "", $2); opts = $2; } else opts = ""; FS = ":"; n = split($NF, parts); if (key == "*") { print key " host==${key};type:=link;fs:=/fs/${key};host!=${key};type:=nfs;rhost:=${key};rfs:=/fs/${key}"; } else { if (NF > 2) print key " host==" parts[1] ";type:=link;fs:=" parts[2] " host!=" parts[1] ";type:=nfs;rhost:=" parts[1] ";rfs:=" parts[2] ";opts:=" opts; else print key " host==" parts[1] ";type:=link;fs:=" parts[2] " host!=" parts[1] ";os!=netbsd1;type:=nfs;rhost:=" parts[1] ";rfs:=" parts[2] " host!=" parts[1] ";os==netbsd1;type:=nfs;opts:=rw,grpid,intr,resvport,proto=\"udp\",vers=2;rhost:=" parts[1] "; } FS = " "; }