NB: The following information is known to be accurate as of revision 851.
Start Template
All programs in
~isg/bin
should really be symlinks to
~isg/bin/symlink_template/start_template
.
This utility is designed to attempt to work in any hostile user environment long enough to
exec
ISGScriptSetup.
It runs in
/bin/bash
to avoid dependencies on Xhierisms (
/xhbin/bash
) or the user environment to determine the location of bash.
This carries a cost; the version of bash on Solaris is 2, which means this has to work in a very old version.
Because of the distrust of the environment, this command takes actions that may be difficult to read; they are broken down here.
Determining the next executable
Because every entry point is a symlink to the same script, it is not clear how it can determine what to execute next.
This is done by looking for a script with the same name, but with
_impl
appended;
this script will then be what actually takes the actions of the command being executed.
It can exist anywhere in the subdirectories of
~isg/bin
.
For example,
-
~isg/bin/runMoss
will run ~isg/bin/moss-files/runMoss_impl
-
~isg/bin/getpermissions
will run ~isg/bin/util/impl/getpermissions_impl
-
~isg/bin/printOut
will run ~isg/bin/rst-files/postprocess/printOut_impl
All of this is handled automatically by
start_template
.
Fail function
This script makes use of a fail function to provide generic abort capability.
fail () {
msg=${1-:Failed to execute setup properly}
echo "$msg; aborting" >&2
exit 125
}
This accepts a number of strings as parameters (supplying "Failed to execute setup properly" as a default if none are provided),
prints them to standard error, and then exits with a non-zero return code.
Else case: Setup has been run
This happens if the condition
[ -z "$ISG_BIN_SETUP_DIRS" ] fails; see
ISGScriptSetup for details.
If this is the case, we assume that setup already ran in this process or a parent process and that we have already been given a sane environment.
Because of this, we immediately try to find the name of the executable being run:
basename "$0" >/dev/null || fail "No runnable basename executable found in inherited path $PATH"
If this presumed sane environment does not contain an executable called
basename
(which it
may not),
we cannot continue, so this should cause an error.
Otherwise, this should return the name of the currently running executable.
Because of this, all we then have to do is:
exec "$(basename "$0")_impl" "$@"
If case: Setup has not been run
If the
setup
utility has not already been run (see
ISGScriptSetup), then we have a more complicated situation.
First, we know that we cannot trust any default utilities, so the PATH should be set to something minimal and safe, and the hash of run commands should be wiped clean.
Note that it is assumed bash will always erase the hash when the PATH is changed like this
(modern versions at least guarantee it), but it's safer to be explicit.
PATH='/bin:/usr/bin'; hash -r
Next, we check for
dirname
in our minimal PATH, similar to how we checked for
basename
in the case above.
If it is not in the path, there is no clear course of action, so we have no choice but to abort.
dirname "$0">/dev/null || fail "Could not run dirname in path $PATH"
If
dirname
exists, then we know we can look in the same directory to find the
setup
program.
The
setup
program, among other things, will provide us with a path with the following properties:
- bash version 3 is the default, so we can assume we have access to its features
- this path also hopefully contains a version of basename
Because of this, we can have
setup
launch bash, and then in turn bash can run basename on the current executable and append '_impl' to the name; this result is saved in a variable for use next.
nextexe="$("$(dirname "$0")/setup" bash -c "eval echo '\$(basename "$0")_impl'")" || fail
If this succeeds, we rely on one additional property of
setup
:
- all subdirectories of
~isg/bin
are included, so it can help us find the _impl
version of the current program
So we run it again, knowing it will execute the
_impl
utility this time.
exec "$(dirname "$0")/setup" "$nextexe" "$@"
Potential Improvements
One thing that stands out above, and is documented in
RT #74634,
is that it is wasteful to call
setup
twice like this.
It should be possible to do the following:
- combine the setup lines into a single more convoluted line... but with the advantage that setup does not have to be called twice serially like this, which will greatly improve the runtime hit of the startup code.
- improve error handling if the executable does not exist, so if this does fail the reason can be determined more easily. This includes the calling user having permission to execute
start_template
but not to execute the next program in the chain (if, for example, it is restricted to the course accounts).