22 October 2012

Configuring AutoFS in FreeBSD

As a follow up to AutoFS in Linux, this post details simple usage of
AutoFS under FreeBSD, as controlled by 'amd'.  The purpose of AutoFS is
to mount volumes as they are needed and unmount them when they are not
in use.  The same setup I used in the Linux write up is presented here,
wherein we have usres' home directories located elsewhere than "/home"
and remote documentation that is occasionally needed on the system.
The intention is presenting standardized directory structures across
systems even if the directory structure of origin may not be standard.
Our details for this are:

        HOST (client):          beastie (10.0.7.135)
        HOST (NFS server):      farnsworth (10.0.7.80)
        OS:                     FreeBSD 8.2
Getting started, I've again set up group "sci" and 2 users, "rfeynman"
and "pcherenkov".  On this host, actual home directories are setup under
"/export/home", though our users' home directories are configured under
"/home":
        beastie [0] /usr/sbin/pw groupadd -n sci
        beastie [0] /usr/bin/grep sci /etc/group
        sci:*:1001:
        beastie [0] /usr/sbin/pw useradd -g 1001 -c "R. Feynman" -d \
        > /export/home/rfeynman -m -s /bin/ksh -n rfeynman
        beastie [0] /usr/sbin/pw useradd -g 1001 -c "P. Cherenkov" -d \
        > /export/home/pcherenkov -m -s /bin/ksh -n pcherenkov
        beastie [0] /usr/bin/tail -2 /etc/passwd
        rfeynman:*:1001:1001:R. Feynman:/export/home/rfeynman:/bin/ksh
        pcherenkov:*:1002:1001:P. Cherenkov:/export/home/pcherenkov:/bin/ksh
In the above, I've used 'pw' to set our users' home directories under
"/export/home", though this is simply so they are created with the
appropriate permissions and "skel" files.  Also, their home directories
really do reside under "/export/home" but for commonality within the
environment, we'll configure them to "/home", letting 'amd' take care
of things later:
        beastie [0] /usr/sbin/pw usermod -d /home/rfeynman -n rfeynman
        pw: WARNING: home `/home/rfeynman' does not exist
        beastie [0] /usr/sbin/pw usermod -d /home/pcherenkov -n pcherenkov
        pw: WARNING: home `/home/pcherenkov' does not exist
        beastie [0] /usr/bin/tail -2 /etc/passwd
        rfeynman:*:1001:1001:R. Feynman:/home/rfeynman:/bin/ksh
        pcherenkov:*:1002:1001:P. Cherenkov:/home/pcherenkov:/bin/ksh
Note in the above, we only tell 'pw usermod' to modify the configured
location of the users' home directories, but not to create them, hence
the missing "-m" option.  Below we have our current mounted file systems
and "fstab" contents (the fstab will not change throughout this set up):
        beastie [0] /bin/df -h
        Filesystem     Size    Used   Avail Capacity  Mounted on
        /dev/da0s1a    5.8G    1.9G    3.5G    35%    /
        devfs          1.0K    1.0K      0B   100%    /dev
        /dev/da0s1d    990M    866K    910M     0%    /var
        /dev/da1s1a    1.9G     40K    1.8G     0%    /export/home
        beastie [0] /usr/bin/grep -v ^# /etc/fstab
        /dev/da0s1b             none            swap    sw              0       0
        /dev/da0s1a             /               ufs     rw              1       1
        /dev/da0s1d             /var            ufs     rw              2       2
        /dev/acd0               /cdrom          cd9660  ro,noauto       0       0
        /dev/da1s1a             /export/home    ufs     rw              2       2

Before configuring and starting 'amd', we do a directory listing of
"/home" and "/export/home", seeing that both are writable by root.  Also,
while our users home directories are now configured under "/home", only "/export/home" has any contents:
        beastie [0] /bin/ls -ld /home /export/home
        drwxr-xr-x  5 root  wheel  512 Oct 21 15:36 /export/home/
        drwxr-xr-x  2 root  wheel  512 Oct 21 15:32 /home/
        beastie [0] /bin/ls -ld /home/* /export/home/*
        ls: /home/*: No such file or directory
        drwxr-xr-x  2 pcherenkov  sci  512 Oct 21 15:36 /export/home/pcherenkov/
        drwxr-xr-x  2 rfeynman    sci  512 Oct 21 15:34 /export/home/rfeynman/
        beastie [1]
We can now start our setup for 'amd' control of the home directories. As a point of understanding, FreeBSD's "autofs" handling differs from that seen elsewhere, such as Linux and Solaris. Whereas the latter 2 actually perform necessary mounts to the locations you configure, FreeBSD's 'amd' mounts file systems as necessary under a common directory (auto_dir) and creates symlinks under the paths you otherwise configure. Using our home directories as the example (which we'll see later), if you configure 'amd' to mount a path under "/home", the actual mount occurs to a private 'amd' controlled directory and a symlink is placed under "/home" referencing back to the 'amd' controlled directory. With that in mind, below we create "/autopriv" for use by 'amd' for its handling of mounts and "/etc/amdmaps" to contain our "autofs" map files:
        beastie [0] /bin/mkdir /autopriv
        beastie [0] /bin/mkdir /etc/amdmaps
Further, we setup a fairly generic 'amd' configuration at "/etc/amd.conf":
        beastie [0] /bin/cat /etc/amd.conf
        # global amd definitions (see 'am-utils' info(1) entry)
        [ global ]
        browsable_dirs =                no
        auto_dir =                      /autopriv
        cache_duration =                300
        dismount_interval =             120
        pid_file =                      /var/run/amd.pid
        restart_mounts =                yes
        search_path =                   /etc/amdmaps:/usr/local/etc/amdmaps
        map_type =                      file

        # amd maps
        [ /home ]
        map_name =                      auto.home
Our settings above in "[ global ]" setup "/autopriv" as the 'amd' mount directory container and disallows browsing or listing of directory structures not in use. Other settings of note is that our map type is set to flat files (rather than NIS, etc.) and a search path for our map files is set. The entry "[ /home ]" starts our auto map configuration and sets the base directory to create links based on the configuration of the subsequent map (auto.home) for "[ /home ]". In reviewing our map "auto.home", the first line begins "/defaults", which sets any default parameters for all other entries in "auto.home". Here, we only have an option of "read-write", which given the following (and only) entry, is fairly useless:
        beastie [0] /bin/cat /etc/amdmaps/auto.home
        /defaults       opts:=rw
        *               type:=link;fs:=/export/home/${key}
The second line begins with a map "key", in this case, I've used "*" which would translate out to the basename of our users' home directories. The subsequent values are configuration parameters to 'amd', semicolon (;) delimited. Since 'amd' doesn't play well with "nullfs" (or loop back) mounts of locally mounted file systems, the first parameter simply tells 'amd' that the references under "/home" should be symlinks (thus why the "rw" option is useless). These symlinks will point back to the values set in the "fs" parameter. Of note, when 'amd' expands the key (*) for the appropriate user upon access / login, the "${key}" variable becomes available, hence the usage with "fs".

Now we need to start up our daemons. Since we will be using NFS with 'amd' in a later example, we'll configure that as well. (If you were only using local resources, like in our home directories example, in addition to the "amd" lines in rc.conf, you would need the "rpcbind" line since 'amd' uses rpc.):
        beastie [0] /usr/bin/egrep 'rpc|nfs|amd' /etc/rc.conf
        rpcbind_enable="YES"
        rpc_lockd_enable="YES"
        rpc_statd_enable="YES"
        nfs_client_enable="YES"
        amd_enable="YES"
        amd_flags="-F /etc/amd.conf -l syslog"
        beastie [0] for i in rpcbind statd lockd nfsclient ; do /etc/rc.d/${i} start ; \
        > sleep 4 ; done
        Starting rpcbind.
        Starting statd.
        Starting lockd.
        NFS access cache time=60
        beastie [0]
        beastie [0] /etc/rc.d/amd start
        Starting amd.
FreeBSD's 'amd' comes with a nice little utility called 'amq', which among other things, allows one to stat the 'amd' process ID (amq -p) and to list the mounted file systems, autofs maps, and their references (amq -m):
        beastie [0] /usr/sbin/amq -p
        1269
        beastie [0] ps p 1269
          PID  TT  STAT      TIME COMMAND
         1269  ??  Ss     0:00.01 /usr/sbin/amd -p -F /etc/amd.conf -l syslog
        beastie [0] /usr/sbin/amq -m
        "root"                                root    1   localhost is up
        /dev/da0s1a             /             ufs     1   localhost is up
        /dev/da0s1d             /var          ufs     1   localhost is up
        /dev/da1s1a             /export/home  ufs     1   localhost is up
        /etc/amdmaps/auto.home  /home         toplvl  1   localhost is up
Back to our home directories, a listing of "/home" and "/export/home" effectively show the same data as before, but note, "/home" is now read only:
        beastie [0] /bin/ls -laF /home /export/home
        /export/home:
        total 10
        drwxr-xr-x  5 root        wheel     512 Oct 21 15:36 ./
        drwxr-xr-x  3 root        wheel     512 Oct 21 15:31 ../
        drwxrwxr-x  2 root        operator  512 Oct 21 15:30 .snap/
        drwxr-xr-x  2 pcherenkov  sci       512 Oct 21 15:36 pcherenkov/
        drwxr-xr-x  2 rfeynman    sci       512 Oct 21 15:34 rfeynman/

        /home:
        total 3
        dr-xr-xr-x   2 root  wheel  512 Oct 21 21:44 ./
        drwxr-xr-x  26 root  wheel  512 Oct 21 21:45 ../
Switching user to "rfeynman" drops us into "/export/home/rfeynman" (same with login), however a simple 'cd' shows us back at "/home/rfeynman". Further, we still have the same file systems mounted and we can see our default "skel" files created:
        beastie [0] /usr/bin/su - rfeynman
        rfeynman@beastie [0] pwd
        /export/home/rfeynman
        rfeynman@beastie [0] cd ; pwd
        /home/rfeynman
        rfeynman@beastie [0] /bin/df -h
        Filesystem               Size    Used   Avail Capacity  Mounted on
        /dev/da0s1a              5.8G    1.9G    3.5G    35%    /
        devfs                    1.0K    1.0K      0B   100%    /dev
        /dev/da0s1d              990M    898K    910M     0%    /var
        /dev/da1s1a              1.9G     40K    1.8G     0%    /export/home
        rfeynman@beastie [0] /bin/ls -laF
        total 20
        drwxr-xr-x  2 rfeynman  sci     512 Oct 21 15:34 ./
        drwxr-xr-x  5 root      wheel   512 Oct 21 15:36 ../
        -rw-r--r--  1 rfeynman  sci     763 Oct 21 15:34 .cshrc
        -rw-r--r--  1 rfeynman  sci     261 Oct 21 15:34 .login
        -rw-r--r--  1 rfeynman  sci     171 Oct 21 15:34 .login_conf
        -rw-------  1 rfeynman  sci     383 Oct 21 15:34 .mail_aliases
        -rw-r--r--  1 rfeynman  sci     343 Oct 21 15:34 .mailrc
        -rw-r--r--  1 rfeynman  sci    1247 Oct 21 21:47 .profile
        -rw-------  1 rfeynman  sci     288 Oct 21 15:34 .rhosts
        -rw-r--r--  1 rfeynman  sci     984 Oct 21 15:34 .shrc
        rfeynman@beastie [0] /bin/ls -laF /home
        total 3
        dr-xr-xr-x   2 root  wheel  512 Oct 21 21:47 ./
        drwxr-xr-x  26 root  wheel  512 Oct 21 21:45 ../
        lrwxrwxrwx   1 root  wheel   21 Oct 21 21:47 rfeynman@ -> /export/home/rfeynman
        rfeynman@beastie [0] touch trashfile
        rfeynman@beastie [0] /bin/ls -li /home/rfeynman/trashfile /export/home/rfeynman/trashfile
        235529 -rw-r--r--  1 rfeynman  sci  0 Oct 21 21:51 /export/home/rfeynman/trashfile
        235529 -rw-r--r--  1 rfeynman  sci  0 Oct 21 21:51 /home/rfeynman/trashfile
        rfeynman@beastie [0] exit
Above, our listing of "/home/rfeynman" shows it to be a symlink back to "/export/home/rfeynman", and as we'd expect, creating and accessing files under "/home/rfeynman" works just fine. Below, is simply a follow up of the above using user "pcherenkov", and again, we see the symlinks for the home directories:
        beastie [0] /usr/bin/su - pcherenkov
        pcherenkov@beastie [0] cd ; pwd
        /home/pcherenkov
        pcherenkov@beastie [0] /bin/ls -laF
        total 20
        drwxr-xr-x  2 pcherenkov  sci     512 Oct 21 15:36 ./
        drwxr-xr-x  5 root        wheel   512 Oct 21 15:36 ../
        -rw-r--r--  1 pcherenkov  sci     763 Oct 21 15:36 .cshrc
        -rw-r--r--  1 pcherenkov  sci     261 Oct 21 15:36 .login
        -rw-r--r--  1 pcherenkov  sci     171 Oct 21 15:36 .login_conf
        -rw-------  1 pcherenkov  sci     383 Oct 21 15:36 .mail_aliases
        -rw-r--r--  1 pcherenkov  sci     343 Oct 21 15:36 .mailrc
        -rw-r--r--  1 pcherenkov  sci    1247 Oct 21 20:59 .profile
        -rw-------  1 pcherenkov  sci     288 Oct 21 15:36 .rhosts
        -rw-r--r--  1 pcherenkov  sci     984 Oct 21 15:36 .shrc
        pcherenkov@beastie [0] /bin/ls -laF /home
        total 4
        dr-xr-xr-x   2 root  wheel  512 Oct 21 21:53 ./
        drwxr-xr-x  26 root  wheel  512 Oct 21 21:45 ../
        lrwxrwxrwx   1 root  wheel   23 Oct 21 21:53 pcherenkov@ -> /export/home/pcherenkov
        lrwxrwxrwx   1 root  wheel   21 Oct 21 21:51 rfeynman@ -> /export/home/rfeynman
        pcherenkov@beastie [0] exit
At this point, let's switch over to "as needed" remote mounts. Having configured beastie as an NFS client earlier and farnsworth already running an NFS server (see nfs.bsd), we can now configure 'amd' to read our "autofs" map for "auto.info". First, I've appended stanza for "[ /opt ]" and its map to "amd.conf", followed by creating the "auto.info" map with the contents seen below:
        beastie [0] /usr/bin/tail -3 /etc/amd.conf
        [ /opt ]
        map_name =                      auto.info

        beastie [0] /bin/cat /etc/amdmaps/auto.info
        /defaults       opts:=intr,bg
        lhc-docs        type:=nfs;opts:=intr,bg,ro;rhost:=farnsworth;\
                                rfs:=/export/${key}
        man             type:=nfs;\
                        addopts:=ro;\
                        rhost:=farnsworth;\
                        rfs:=/export/man
We still have our "/defaults" line, setting our base options for the "auto.info" entries. Our keys are configured as "lhc-docs" and "man", both of which will be presented again as symlinks under "/opt". Our 'amd' parameters set both as type "nfs" and the remote host (rhost) as farnsworth. In the "lhc-docs" entry, we've overridden the default options (opts) and configured them to NFS options "intr,bg,ro". The remote filesystem (rfs) is "/export/${key}", where key will be expanded to "lhc-docs", which is the actual path on the NFS server farnsworth. In the "man" entry, we've added to the default options (addopts), including "ro". Additionally, rather than using a "${key}" variable, we've simply set it directly. Of note in the above, while semicolons (;) delimit parameters to 'amd' and white space isn't necessarily a problem, all options to a key (lhc-docs, man) must be contained on a single line. To keep a map files easily readable, you can break to the next line, providing you are using escapes (\). Now that are configuration is complete, we'll restart 'amd' so it rereads its configuration and stat 'amd' with 'amq -m' again, verifying it is reading our new map for "auto.info":
        beastie [0] /etc/rc.d/amd restart
        Stopping amd.
        Waiting for PIDS: 1269.
        Starting amd.
        beastie [0] /usr/sbin/amq -m
        "root"                                root    1   localhost is up
        /dev/da0s1a             /             ufs     1   localhost is up
        /dev/da0s1d             /var          ufs     1   localhost is up
        /dev/da1s1a             /export/home  ufs     1   localhost is up
        /etc/amdmaps/auto.home  /home         toplvl  1   localhost is up
        /etc/amdmaps/auto.info  /opt          toplvl  1   localhost is up
Switching user to "pcherenkov", we make sure that our new "autofs" configuration will work for our users:
        beastie [0] /usr/bin/su - pcherenkov
        pcherenkov@beastie [0] /bin/ls -al /opt
        total 3
        dr-xr-xr-x   2 root  wheel  512 Oct 21 22:27 .
        drwxr-xr-x  26 root  wheel  512 Oct 21 22:27 ..
        pcherenkov@beastie [0] /bin/ls -al /opt/lhc-docs
        lrwxrwxrwx  1 root  wheel  40 Oct 21 22:28 /opt/lhc-docs -> /autopriv/farnsworth/export/lhc-docs
        pcherenkov@beastie [0] /bin/ls -al /opt/lhc-docs/
        total 340
        drwxr-xr-x  2 root  wheel     512 Oct 21 16:06 .
        dr-xr-xr-x  4 root  wheel     512 Oct 21 22:28 ..
        -rw-r--r--  1 root  wheel    1491 Oct 21 16:06 section.1
        -rw-r--r--  1 root  wheel  109208 Oct 21 16:06 section.2
        -rw-r--r--  1 root  wheel   45224 Oct 21 16:06 section.3
        -rw-r--r--  1 root  wheel  106232 Oct 21 16:06 section.4
        -rw-r--r--  1 root  wheel   76056 Oct 21 16:06 section.5
        pcherenkov@beastie [0] /bin/df -h | /usr/bin/grep lhc-docs
        farnsworth:/export/lhc-docs    5.8G    2.0G    3.4G    37%    /autopriv/farnsworth/export/lhc-docs
Above, we see that a directory listing of "/opt" returns nothing of interest due to our original 'amd' configuration disallowing directory browsing. A directed listing of "/opt/lhc-docs", however, shows it to be a symlink under the 'amd' controlled mount directory "/autopriv". A further listing and we can stat the contents. The last thing we see is that we now have an NFS mount back to farnsworth, courtesy of 'amd'. Below, we see the contents of "/opt/lhc-docs" are fully accessible for reading:
        pcherenkov@beastie [0] /usr/bin/head -10 /opt/lhc-docs/section.1
        [http://public.web.cern.ch/public/en/lhc/lhc-en.html]

        The Large Hadron Collider
        Our understanding of the Universe is about to change...

        The Large Hadron Collider (LHC) is a gigantic scientific instrument near
        Geneva, where it spans the border between Switzerland and France about
        100m underground. It is a particle accelerator used by physicists to
        study the smallest known particles – the fundamental building blocks of
        all things. It will revolutionise our understanding, from the minuscule
Similary, we see below that the contents of "/opt/man" are accessible upon request, simply by attempting to access a file contained on farnsworth's remotely exported filesystem:
        pcherenkov@beastie [0] /usr/bin/gunzip -c /opt/man/man1/vi.1.gz | \
        > /usr/bin/groff -Tascii -man - | /usr/bin/head -20
        VI(1)                                                                    VI(1)



        NAME
               ex, vi, view - text editors

        SYNOPSIS
               ex [-eFGRrSsv] [-c cmd] [-t tag] [-w size] [file ...]
               vi [-eFGlRrSv] [-c cmd] [-t tag] [-w size] [file ...]
               view [-eFGRrSv] [-c cmd] [-t tag] [-w size] [file ...]

        LICENSE
               The  vi  program  is  freely redistributable.  You are welcome to copy,
               modify and share it with others under  the  conditions  listed  in  the
               LICENSE  file.   If any company (not individual!) finds vi sufficiently
               useful that you would have purchased it, or if any  company  wishes  to
               redistribute it, contributions to the authors would be appreciated.

        DESCRIPTION
        pcherenkov@beastie [0] man -w -M /opt/man vi
        /opt/man/man1/vi.1.gz
Seen below, I've simply included a few checks reviewing the state of our mounts and symlinks:
        pcherenkov@beastie [0] /sbin/mount | /usr/bin/grep farnsworth
        farnsworth:/export/man on /autopriv/farnsworth/export/man (nfs, read-only)
        farnsworth:/export/lhc-docs on /autopriv/farnsworth/export/lhc-docs (nfs, read-only)
        pcherenkov@beastie [0] /bin/ls -al /opt
        total 4
        dr-xr-xr-x   2 root  wheel  512 Oct 21 22:33 .
        drwxr-xr-x  26 root  wheel  512 Oct 21 22:27 ..
        lrwxrwxrwx   1 root  wheel   40 Oct 21 22:33 lhc-docs -> /autopriv/farnsworth/export/lhc-docs
        lrwxrwxrwx   1 root  wheel   35 Oct 21 22:32 man -> /autopriv/farnsworth/export/man
        pcherenkov@beastie [0] /bin/df -h | /usr/bin/grep farnsworth
        farnsworth:/export/man         5.8G    2.0G    3.4G    37%    /autopriv/farnsworth/export/man
        farnsworth:/export/lhc-docs    5.8G    2.0G    3.4G    37%    /autopriv/farnsworth/export/lhc-docs
see also:
    Configuring AutoFS in Linux
    http://www.am-utils.org/docs/am-utils/am-utils-all.html
    Configuring NFS in FreeBSD (nfs.bsd)