From 8f051d8ef6a9bc03da3c68da518021a6b222c176 Mon Sep 17 00:00:00 2001 From: "Yann E. MORIN\"" Date: Sat, 29 Aug 2009 18:27:47 +0200 Subject: [PATCH] tool wrapper: add initial wrapper coded in C Add an initial wrapper: - find the realpath of the tool being called - add the '.' in front of the tool name - add the '/lib' dir to the base dir of the tool - set and export LD_LIBRARY_PATH - execve the real tool --- scripts/wrapper.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 scripts/wrapper.c diff --git a/scripts/wrapper.c b/scripts/wrapper.c new file mode 100644 index 00000000..dbbcdd9d --- /dev/null +++ b/scripts/wrapper.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include +#include + + +/* Needed for execve */ +extern char **environ; + +int main( int argc, + char** argv ) +{ + char *fullname; /* 'fullname' is used to store the absolute path to the + tool being executed; it serves as a base to compute + the realname of that tool, and the directory holding + our runtime libraries */ + char *realname; /* 'realname' is the real name of the tool, that is what + the wrapper is currently impersonating */ + char *basedir; /* 'libdir' contains our runtime libraries */ + + char *lastslash; /* Temporary variables now */ + char *ldlibpath; + size_t len; + int execve_ret; + + /* In case we have a relative or absolute pathname (ie. contains a slash), + * then realpath wll work. But if the tool was found in the PATH, realpath + * won't work, and we'll have to search ourselves. + * This if{}else{} block allocates memory for fullname. */ + if( strchr( argv[0], '/' ) ) { + fullname = (char*) malloc( PATH_MAX * sizeof(char) ); + if( ! realpath( argv[0], fullname ) ) { + perror( "tool wrapper" ); + exit( 1 ); + } + } else { + char *path; + char *mypath; + char *colon; + char *testname; + struct stat st; + + fullname = NULL; + colon = mypath = path = strdup( getenv( "PATH" ) ); + while( colon ) { + colon = strchr( mypath, ':' ); + if( colon ) { + *colon = '\0'; + } + testname = strdup( mypath ); + testname = (char*) realloc( testname, strlen( testname ) + + strlen( argv[0] ) + + 2 * sizeof(char) ); + memset( testname + strlen( testname ), + 0, + strlen( argv[0] ) + 2 * sizeof(char) ); + strcat( testname, "/" ); + strcat( testname, argv[0] ); + if( stat( testname, &st ) == 0 ) { + /* OK, exists. Is it a regular file, or a + * symlink, which the current user may execute? */ + if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) { + fullname = strdup( testname ); + break; + } + } + free( testname ); + mypath = colon + 1; + } + free( path ); + if( ! fullname ) { + fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] ); + exit( 1 ); + } + } + + /* Duplicate my own name to add the 'dot' to tool name */ + realname = strdup( fullname ); + realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) ); + realname[ strlen( realname ) + 1 ] = '\0'; + + /* Add the dot after the last '/' */ + lastslash = strrchr( realname, '/' ); + memmove( lastslash + 1, lastslash, strlen( lastslash ) ); + *( lastslash + 1 ) = '.'; + + /* Compute the basedir of the tool */ + basedir = strdup( fullname ); + lastslash = strrchr( basedir, '/' ); + *lastslash = '\0'; + lastslash = strrchr( basedir, '/' ); + *lastslash = '\0'; + + /* Append '/lib' */ + len = strlen( basedir ); + basedir = (char*) realloc( basedir, len + 5 ); + *( basedir + len ) = '\0'; + strcat( basedir, "/lib" ); + + /* Now add the directory with our runtime libraries to the + front of the library search path, LD_LIBRARY_PATH */ + ldlibpath = getenv( "LD_LIBRARY_PATH" ); + if( ldlibpath ) { + basedir = (char*) realloc( basedir, strlen( basedir ) + + strlen( ldlibpath ) + + 2 * sizeof(char) ); + strcat( basedir, ":" ); + strcat( basedir, ldlibpath ); + } + + if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) { + errno = ENOMEM; + perror( "tool wrapper" ); + exit( 1 ); + } + + /* Execute the real tool, now */ + execve_ret = execve( realname, argv, environ ); + + /* In case something went wrong above, print a + diagnostic message, and exit with error code 1 */ + perror( "tool wrapper" ); + return 1; +}