Radmind and mountpoints

radmind iconYesterday we had a near-disaster where another admin created a mountpoint at /mnt and mounted an NFS filesystem for testing. After testing, he proceeded to run the radmind tools to update his machine. He noticed that radmind was scanning the contents of /mnt and aborted the run. If he had not aborted it, it’s likely that lapply would have started deleting items on that mount.

In the dim, dark past I asked for a feature for fsdiff that would cause it to ignore remotely mounted filesystems to prevent just this problem, having seen it crop up a few times here, usually due to an error.

Normally this is not a problem, as things like AFP and SMB servers normally mount under paths that are already in a negative transcript – places like /Network, /Volumes, and /automount. But a user with sudo rights (or an admin) can create mountpoints virtually anywhere and mount things. A more likely scenario that can lead to this type of problem is implementing classic UNIX NFS automounts like /home – a radmind administrator’s mistake in a transcript could lead to lapply trying to remove the contents of /home!

When this almost happened again yesterday, I had the flash of insight that I could script around the problem, and I came up with the attached script.

The concept is simple:
The script uses the ‘mount” command to get a list of mounted filesystems of type NFS, AFP, and SMB. It then parses the list to find the mountpoints as pathnames. Each of these pathnames is checked to see if it or its immediate parent is already part of a negative transcript. If a pathname (and its parent) is determined to not be in any negative, a new negative transcript is generated containing transcript lines for each mountpoint not already listed in a negative transcript.

This new transcript is written to /var/radmind/client, and /var/radmind/client/command.K is modified, adding a negative transcript entry to the very end of the command file.

The sequence of operations becomes:

  1. Run fsdiff to get an updated command file and updated transcripts.
  2. Run make_mount_neg_transcript to add mountpoints as a negative transcript if needed
  3. Run fsdiff and the rest of the radmind tools as normal.

This script has not had a lot of testing, and may not be appropriate for all environments. In fact, it probably won’t be needed in _most_ environments. Please test thoroughly before using. (Hint: run it and look at the end of /var/radmind/client/command.K and the contents of /var/radmind/client/generated_mounts-neg.T) Feedback welcome.

And now… the script:


#/usr/bin/perl -w

# make_mount_neg_transcript
#
# This script is intended to prevent fsdiff from looking into
# remotely mounted filesystems, and therefore preventing lapply
# from attempting to modify remote filesystems. 
#
# You'd run this script after ktcheck, but before fsdiff.
# It modifies /var/radmind/client/command.K to refer to a new
# transcript - gnerated_mounts-neg.T, which contains entries
# for all current NFS, AFP and SMB mounts that are not already
# in a negative transcript.
#
# by Greg Neagle, Walt Disney Feature Animation

use strict;

# create a temporary file
my $tempfile = `/usr/bin/mktemp /tmp/mnt.XXXXXX`;
if ($?) {
   $tempfile = "/tmp/mnt_trans.$$.T";
}
chomp $tempfile;
my $mount_neg_file = 
   "/var/radmind/client/generated_mounts-neg.T";
my $command_file = "/var/radmind/client/command.K";
if (-f "$tempfile") {
   unlink $tempfile;
}

# get list of current NFS, AFP, and SMB/CIFS mounts 
my $mountlist = `/sbin/mount -t nfs,afpfs,smbfs`;
my @mounts = split /\\n/, $mountlist;
for my $mount (@mounts) {
   # get the pathname from /sbin/mount output
   $mount =~ /^.* on (\\/.*$)/;
   my $pathname = $1;
   # strip off the info in parenthesis at the end of the line
   # if the pathname has parentheses 
   # (like /Applications (Mac OS 9)) this will break. 
   # Try not to mount things on paths like that!
   $pathname =~ s/ \\(.*\\)$//;
   my $negativeFlag = 0;
   if ($pathname) {
      # check to see if the path is already
      # in a negative transcript
      my $radstat = `/usr/local/bin/twhich "$pathname"`;
      chomp $radstat;
      if ($radstat =~ /^# Negative$/m) {
         # path is already negative
         $negativeFlag = 1;
      } elsif ($radstat eq "") {
         # path was in no transcript, so check to see if its
         # parent is in a negative transcript
         my $parent = `/usr/bin/dirname "$pathname"`;
         chomp $parent;
         $radstat = `/usr/local/bin/twhich "$parent"`;
         if ($radstat =~ /^# Negative$/m) {
            # parent dir is in a negative transcript
            $negativeFlag = 1;
         }
      }
      unless ($negativeFlag) {
         # neither path nor its parent were in a negative
         # transcript so create a transcript entry for 
         # this pathname
         my $transcriptline = 
            `/usr/local/bin/fsdiff -1 "$pathname"`;
         chomp $transcriptline;
         `echo "$transcriptline" >> $tempfile`;
      }
   }
}
 
if (-f "$tempfile") {
   # sort the transcript lines we generated so the radmind tools 
   # will be happy and put the output in /var/radmind/client
   `/usr/local/bin/lsort -o $mount_neg_file $tempfile`;
   # we don't need the temp file any more
   unlink $tempfile;
   my $transcript_name = `basename "$mount_neg_file"`;
   chomp $transcript_name;
   # add the transcript as a negative entry 
   # in the local command file
   if (!(`grep $transcript_name $command_file`)) {
      `echo "# Script-generated transcript of mountpoints" >> $command_file`;
      `echo "n $transcript_name" >> $command_file`;
   }
}

Radmind and mountpoints