Classic Shell Scripting - Arnold Robbins [111]
for MAIL in /bin/mailx /usr/bin/mailx /usr/sbin/mailx /usr/ucb/mailx \
/bin/mail /usr/bin/mail
do
test -x $MAIL && break
done
test -x $MAIL || error "Cannot find mail client"
If the user supplied additional source directories, we put them at the front of the default list. The possibility of replacing the default list does not appear to have any value, so we don't provide a way to do so:
SRCDIRS="$altsrcdirs $SRCDIRS"
Correct setting of the final userhosts list is complex, and requires explanation. We have three potential sources of data for the list:
Command-line —on options added their arguments to the userhosts variable.
Command-line —userhosts options added files, each containing zero or more build-host specifications, to the ALTUSERHOSTS variable.
The defaultuserhosts variable contains the name of a file that supplies default build-host specifications, to be used only when no command-line options provide them. For most invocations of build-all, this file supplies the complete build list.
If the userhosts variable contains data, then the contents of any files recorded in ALTUSERHOSTS must be added to it to obtain the final list:
if test -n "$userhosts"
then
test -n "$ALTUSERHOSTS" &&
userhosts="$userhosts `$STRIPCOMMENTS $ALTUSERHOSTS 2> /dev/null`"
Otherwise, the userhosts variable is empty, and there are still two possibilities. If ALTUSERHOSTS was set, we leave it untouched. If it was not set, we set it to the default file. Then we assign the contents of the files in ALTUSERHOSTS to the userhosts variable for the final list:
else
test -z "$ALTUSERHOSTS" && ALTUSERHOSTS="$defaultuserhosts"
userhosts="`$STRIPCOMMENTS $ALTUSERHOSTS 2> /dev/null`"
fi
Before we begin the real work, a sanity check is essential to ensure that we have at least one host. Although the inner loop would not be executed in such a case, we want to avoid unnecessary directory and log-file creation. If userhosts is empty, it was probably user error, so a reminder of how to use the program is called for:
test -z "$userhosts" && usage_and_exit 1
Here at last is the outer loop of the program, a loop over packages. The shell does not execute the loop body if the argument list is empty, which is exactly what we want. The loop is large enough that we present only a few lines at a time:
for p in "$@"
do
The work of locating the package archive in the source directory list is delegated to the find_package function, which leaves its results in global variables—among them, PARFILE (package archive file):
find_package "$p"
If PARFILE is empty, we issue a complaint on standard error and continue with the next package:
if test -z "$PARFILE"
then
warning "Cannot find package file $p"
continue
fi
Otherwise, if a log directory was not supplied, or was but is not a directory or is not writable, we attempt to create a subdirectory named logs underneath the directory where the package archive was found. If that directory cannot be found, or is not writable, then we try to put the logs under the user's $HOME/.build/logs directory, or else in a temporary directory. We prefer the less-volatile temporary directories over /tmp, which is usually lost at a reboot, so we use it only as a last resort:
LOGDIR="$altlogdir"
if test -z "$LOGDIR" -o ! -d "$LOGDIR" -o ! -w "$LOGDIR"
then
for LOGDIR in "`dirname $PARFILE`/logs/$p" $BUILDHOME/logs/$p \
/usr/tmp /var/tmp /tmp
do
test -d "$LOGDIR" || mkdir -p "$LOGDIR" 2> /dev/null
test -d "$LOGDIR" -a -w "$LOGDIR" && break
done
fi
* * *
Tip
The dirname command is the companion to the basename command that we introduced in Section 8.1. dirname strips all characters in its argument from the final slash onward, recovering a directory path from a full pathname, and reports