Cover V07, I07
Article

jul98.tar


SLAMming Symbolic Links

Edward Quillen

Symbolic links are one of the most useful and powerful features of UNIX. However, they also can become a management nightmare. Symbolic links just are too easy to create. In the blink of an eye, a link can be created that makes accessible an entire directory tree of data from some far off filesystem. And once a path to data exists, it will live on, embedded in login scripts, configuration files, and who knows where else, seemingly until the end of time. That may or may not be what you want. In any case, detection of symbolic links and their properties can be a handy management tool. This is what led me to develop the program that I call SLAM (Symbolic Link Auto Management).

SLAM's major feature is symbolic link change detection. It detects the following major incidents (and some more obscure ones discussed later):

  • Creation of a new link
  • Deletion of an old link
  • Changing of a link's value

It accomplishes this by creating a database of all links in a defined set of directories and directory trees, which I call "linksets". It can then compare current link data with past link data to determine changes.

SLAM was implemented with Perl5 for its obvious advantages of features and portability. The SLAM code, however, is not very "perlish" since I am a C programmer by training. Although the code works well, I'm sure it could be much more efficient. To strictly control directory traversal, there is OS-specific Perl code embedded in a couple of modules. Support for SunOS, Solaris, HP-UX, AIX, OSF, and Linux currently exists, and it would be easy to add others. (SLAM and other listings mentioned in this article can be found at: ftp.mfi.com in /pub/sysadmin/ or www.samag.com.

SDBM is used to implement the database. SDBM is a "key-based" database implementation similar to the classic DBM used in NIS for map storage. The benefits of using SDBM are that it provides a sizable performance advantage over flat files and is supported in the base installation of Perl5. Currently the following link properties are stored in the database:

  • Link full path
  • Link value (destination)
  • Link change time (ctime)
  • Link mode
  • Link uid and gid

The creation time, mode, uid, and gid are currently not used by SLAM but are kept for other uses of the data or for future features.

When SLAM is used to manage a directory of databases (default behavior), it stores databases using the following naming structure:

slam-<hostname>-<linksetname>-<timestamp>[.dir|.pag]

For all unique hostname and linksetname pairs, a special set of links are maintained with the timestamp field set to the string "last", so that easy access to the last database exists. The hostname field is used to allow the data from multiple UNIX nodes to be kept in the same directory for global processing of links and easier management. The linksetname field refers to an identifier that signifies a set of directory and directory tree definitions and has the following syntax:

<linksetname> [tree=<dir>] [tree_localdisk=<dir>] \
[tree_private=<dir>]

[dir=<dir>] [linkdef=<linkpath>^<linkvalue>]

tree - Traverse a directory tree starting at dir

tree_localdisk - Same as tree except only crossing filesystems if the filesystems are local and meaningful

tree_private - Same as tree except never crossing filesystem boundaries

dir - Process a directory without descending down branches

linkdef - Used for a special SLAM function discussed later

Running SLAM

SLAM consists of one executable file: slam. I created it that way by mashing all the modules together into one file so that it can be placed anywhere and work after defining the location of the Perl5 executable in the first line of the file. It has a verbose, yet restrictive command line syntax. I like verbose arguments for programs that are not commonly hand entered, because they tend to be self-documenting. Restrictive syntax results from sheer laziness on the programmer's part. The minimal syntax is as follows:

slam -dbdir=<dirname> -cmd=[check|checkdef|dump] \
-linkset=<name> [-justbuild] [-linksetdef="name arg1 ..." | -linksetfile=[<file>||command]] [-action=[fix|nolog||command]

Other Goodies

Apart from SLAM's major feature of storing links in a database and detecting link changes, it also has the following features:

  • Maintenance of defined links - SLAM can also examine, create, or fix well-defined symbolic links on your systems. Using the linkdef parameter of a linkset definition, multiple links along with their values can be defined and then processed by SLAM using the checkdef command.
  • Link reference existence checks - Using the -checkdest flag on the command line, SLAM can check for the existence of the object a link is pointing to during a database build or when a checkdef is performed.
  • Directory recursion checks - SLAM can detect links that point to directories that are ancestors of the link by using the -checkrecursion flag on the command line. This can be used to solve that pesky problem of infinite directory traversals.
  • Output of all link database info - Using the dump command, SLAM can display all the link data in the current databases (-dbfiles=all) or in specific files (-dbfiles=<file w/ wildcards>). Hostname and linksetname fields are prepended to the output to make searches more productive. A separate utility named rrp is provided to resolve relative paths and can be used in conjunction with the link value dumps to do even more exact searches. I'll leave it to you to write the scripts for this.
  • Handy modules for Perl5 junkies - To control directory traversals done by SLAM, I developed a module named FindPlus, which has a few more features than the standard File::Find that comes with Perl. Namely, it integrates with another module I developed, called MountedFileSystems, which gives details about all currently mounted filesystems. These modules are handy for administrators who need to simulate the -mount or -xdev arguments of the find program for controlling directory traversal.

Examples

Example 1: Build a database of all links on a system.

slam -cmd=check -justbuild -dbdir=/linkdbdir \
-linkset=first \ -linksetdef="first tree_localdisk=/"

Example 2: Check for any changes some time later, stopping logging to stdout and calling the program /lchg for each event.

slam -cmd=check -dbdir=/linkdbdir -linkset=first \
-linksetdef="first tree_localdisk=/" \
-action="|/lchg" -action=nolog

Arguments to /lchg will be:

<timestamp> <hostname> <event> <linkpath> <linkvalue> \
[<auxlinkvalue>]

where event can be: notexist, incorrect, newlink, nodest, recursive.

Example 3: Make sure a set of defined links exist and are correct on a node. Build an NIS map called slam-linksets with the following data:

key=ls1   value="linkdef=/usr/local^/net/local"
key=ls1 value="linkdef=/usr/myapp^/net/myapp"

slam -cmd=checkdef -linkset=ls1 -linksetfile="|ypcat \
slam-linksets" -action=fix

Example 4: Dump all links from all systems with a : delimiter as opposed to the default ^ delimiter.

slam -cmd=dump -dbdir=/linkdbdir -dbfiles=all -delim=":"

Installation Example

The ideal way to install SLAM is to untar the source (which can be found at www.samag.com) in a directory that is NFS accessible from all your machines (which I will call <slamdir> for the following example). If you will be using SLAM to scan system links, it is also beneficial to maintain a central database directory that allows root to write to it. Let's call this directory <slamdir>/dbdir.

Next, run an initial SLAM database build on all your systems by running the following command on each of your machines:

<slamdir>/slam -cmd=check -justbuild -dbdir=<slamdir>/dbdir \
-linkset=all -linksetdef="all tree_local disk=/"

To set up SLAM to monitor all link changes once a week on all systems, you can just add the following root crontab entry on all your machines:

0 2 * * * <slamdir>/slam -cmd=check -dbdir=<slamdir>/dbdir \
-linkset=all -linksetdef="all tree_localdisk=/"

A list of all link changes will be mailed to root on each system due to the fact that the change messages are logged to stdout by default. Some sample messages follow:

19980221023432:host1:notexist:/home/joe/testlink
19980221023632:host2:newlink:/home/bobj/work/plan:.. \
/current.plan

Of course, SLAM can be used in many different ways with many levels of complexity. The above is a simple example that provides a large amount of link activity information with a minor amount of time invested.

Summary

I have discussed some of the major features of SLAM in this article, but certainly did not cover all of the possibilities. SLAM is really a framework in which useful features can be implemented in companion scripts. Thus, you will need to tweak SLAM for your site to receive maximum benefit. In summary, I realize the problem of symbolic link management is something administrators don't usually spend much time fretting about. However, SLAM can take you a long way toward your solution.

About the Author

When not working on consulting projects for Sprint Paranet, Ed spends time with his wife, Jill, and his 18-month-old daughter, Megan, who is the supervising admin for their home network. You can reach Ed at quillen@usa.net.