Use of "trampoline" executables

Making products such as perl, tk, and python into ups products adversely affects their usability as scripting langauages. Previous attempts at solving this problem have involved using the /usr/local/products convention, have proven administratively difficult, epecially in the area of creating a sitewide products area in AFS space, and for off-site users who do not neccesarily have write access to /usr/local. This document proposes a new approach to solving these problems, the use of trampoline executables.

The Goal

The goal of this proposal is that scripting languages like perl, tk, and python, will be usable via executable scripts which are stored in a file beginning with:
#!/usr/local/bin/perl
or
#!/usr/local/bin/python
etc.;

This is what users of those scripting languages from places other than Fermilab are used to.

The problem

Making products such as perl, tk, and python into ups products adversely affects their usability as above, because things like libraries, configuration files, etc. are only locatable if the product has been setup, or if some other method of locating the product's required files is established. So even if you copy or link the executable to /usr/local/bin, the product still doesn't work, because it can't find its initialization files, libraries, etc.

This also makes other approaches, like using:

#!/bin/env perl
problematic. Once again, the script doesn't work unless the product is already setup.

The /usr/local/products "solution"

Previous attempts at solving this problem have involved using the ups configure facility, to create a symlink forest down in /usr/local/products so that those products do not have to be set up to work. Instead, they have a compiled-in pathname rooted at /usr/local/products, which is used to locate library files, config files, etc.

Once this approach was adopted, this was the only mechanism used to locate the config files, library files, etc. so that if the symbolic link was missing the product wouldn't work, regardless if it was set up.

This meant that people who did not have write permission in /usr/local/products could not install these products and make them useful, meaning that these products were in general not usable by off-site users.

It also lead to problems where products areas are shared by multiple systems; each separate /usr/local area needs to have the ups configure run on it. So, depending on the configuration of systems, you would get the product working on one node and not on others. As a final bit of confusion, there is no way to un-configure the product on more than one node, (since unconfigure is a side effect of undeclare), so the old symbolic links never get cleaned up in general.

The sharing problems above makes using these products in a site-wide product server system, such as the OSS department is trying to build in AFS space, quite impractical.

The "trampoline" executable approach

An alternative is to build a trampoline executable, which can be put in directories like /usr/local/bin (or anywhere else that is convenient for or writable by the installer), which allows the:
#!/usr/local/bin/perl
header on the script to work. A trampoline executable looks something like:
#include <stdlib.h>
#define MAXPATHLEN 1024

char python_dir[MAXPATHLEN] = 
		"PYTHON_DIR_PUT_HERE_WHEN_PYTHON_IS_CONFIGURED"
char python[MAXPATHLEN];
char pythonpath[MAXPATHLEN*5];
char pythonhome[MAXPATHLEN];
char error[MAXPATHLEN+10];

int
main(int argc, char  **argv) {

    sprintf (pythonpath, 
            "PYTHONPATH=%s/lib/python1.5:%s/lib/python1.5/lib-dynload:%s/lib/python1.5/lib-stdwin:%s/lib/python1.5/lib-tk:%s/lib/python1.5/plat",
	    python_dir, 
	    python_dir, 
	    python_dir, 
	    python_dir, 
	    python_dir);
    sprintf(pythonhome,"PYTHONHOME=%s",python_dir);
    sprintf(python, "%s/bin/python", python_dir );

    putenv(pythonhome);
    putenv(pythonpath);
    execv(python, argv );
    sprintf(error, "can't exec %s:", python);
    perror(error);
}
In other words, it sets the environment variables that the product setup script would have set, and exec's the interpreter executable in the product; in effect "bouncing" the exec() off of the first executable and onto the interpreter, hence the name trampoline.

A similar, although slower, alternative is to have an "always run the current version" trampoline script, which execs a shell which actually sources the "setups" script, and sets up the product before executing the interpreter.

Solution Strategies

For backwards compatability with past "shells" product installations, the new, standlone, perl product will provide a trampoline executable that can be installed in /usr/local/bin. Similar trampoline scripts can be provided for other interpreted languages.

In addition the following concrete proposals are being implemented:

24 April 1998
Comments? Send them to uas-group@fnal.gov