Radmind: converting to case-insensitive transcripts


Radmind, being a set of UNIX tools, originally supported only case-sensitive transcripts. Mac OS X’s HFS+ filesystem, developed by Apple pre-NeXT purchase, is a case-preserving, case-insensitive filesystem.

Support for case-insensitive transcripts was later added to the radmind tools.

As it turns out, it is perfectly possible to use radmind with case-sensitive transcripts to manage an OS X HFS+ filesystem. There are sometimes a few annoyances, but it generally works OK. Worst case, you might have to run the radmind tools twice to get the filesystem update when there is a case change: the first run might remove the lowercase version of the file, and the second run would install the uppercase version. Or a sharp radmind admin might be able to avoid the problem altogether by renaming files in troublesome transcripts.

One situation where needing multiple runs of the radmind tools to get to a complete filesystem is problematic is during OS updates. You really want to have a completely successful lapply run so that the filesystem is in a consistent, bootable state. If lapply fails halfway through, you might end up with an unbootable startup disk.

So when doing major updates, like, say, from 10.4.x to 10.5.x, you need to minimize all failure modes. While working on getting radmind to update our Macs from Tiger to Leopard, lapply would consistently fail because of case changes in filesystem objects. Instead of playing whack-a-mole trying to find and rename all the changed case filesystem objects, I decided to make the transition to case-insensitive transcripts.

This was not trivial. We have very modular transcripts, typically describing a single application or single set of configuration changes. In fact, right now, there are 961 transcripts sitting in the top level of my /var/radmind/transcript directory. So I needed a way to convert all of them to case-insensitive — simply recreating them from scratch was not an option.

It certainly is possible to convert existing case-sensitive transcripts to case-insensitive. The lsort tool that is part of the radmind tool set will resort transcripts either case-sensitively or case-insensitively. The bigger problem occurs when the transcript contains hard links. Given a transcript like this:


f /Z 0644 0 0 1088185725 0 2jmj7l5rSw0yVb/vlWAYkK/YBwk=
h /a /Z
h /m /Z

If you run it through lsort -I, you get this:


h /a /Z
h /m /Z
f /Z 0644 0 0 1088185725 0 2jmj7l5rSw0yVb/vlWAYkK/YBwk=

which won’t lapply correctly, since you are creating hard links to files that don’t exist yet. Instead, you need it to look like this:


f /a 0644 0 0 1088185725 0 2jmj7l5rSw0yVb/vlWAYkK/YBwk=
h /m /a
h /Z /a

AND you need the actual files under /var/radmind/file moved around so that they match the transcript. Yuck. So I banged out a script that does all this. It’s a bit of a mess, and probably relies on assumptions about my environment that don’t apply in yours. Still, you may be able to modify it to fit your needs.

The usage is:

converttocaseinsensitive transcript.T

which results in a new case-insensitive loadset at

/var/radmind/transcript/caseinsensitive/transcript.T

and

/var/radmind/files/caseinsensitive/transcript.T/

To minimize disk usage, I symlink where possible, for example, in cases where the case-insensitive transcript is the same as the case-sensitive one, or where the file set has no hard links (and therefore needs no modifications). The assumption is that you are using an HFS+ volume for your radmind data storage; if you are using a case-sensitive volume you’ll need to do more work to rename the actual files…

Here is the script.

Radmind: converting to case-insensitive transcripts

4 thoughts on “Radmind: converting to case-insensitive transcripts

  1. That’s a good way to handle it server-side. We do something similar, but instead we touch the file on the hard drive before running lapply in a pre-apply script:

    #! /bin/sh

    # work around a hardlink ordering problem that occurs
    # when a hardlink’s source is case-insensitively
    # alphabetically greater than the target. E.g:
    #
    # h ./usr/share/man/man3/atomic.3 ./usr/share/man/man3/OSAtomicAdd32.3
    #
    # If the source doesn’t exist, and we run case-
    # insensitively, the hardlink will fail because
    # there’s nothing to link to.
    #
    # The workaround checks for such lines, and touches
    # the source file, preventing hardlink errors.

    PATH=/bin:/usr/bin; export PATH

    trans=”$1″

    if [ -z “${trans}” ]; then
    logger -i -t $0 No arguments
    exit 0
    fi

    cat “${trans}” | awk ‘{ if ( $1 == “h” ) { \
    if ( tolower($2) < tolower($3) ) { \
    if ( system( “test -e ” $3 ) != 0 ) { \
    system( “touch ” $3 );
    } \
    } \
    } \
    }’

    exit 0

  2. Neat. This should allow you to store only one version of the transcripts/loadsets on the server, and then dynamically resort as needed locally. Is that what you are doing?

  3. Andrew Mortensen says:

    I wrote that script when I was making the transition to case-insensitive transcripts in the Mac environment at Umich. I recall re-sorting the local copies of the transcripts before running the update. The trick was to do it without triggering ktcheck updates. Jeff, how are you using the script these days?

  4. These days we still have it as a pre-apply script, but I’m not sure how often we run into this issue (because the script would touch the file). We’re using case-insensitive, relative transcripts exclusively still.

Comments are closed.