tool wrapper: add initial wrapper coded in C
author"Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat Aug 29 18:27:47 2009 +0200 (2009-08-29)
changeset 1492b97f8fa54d67
parent 1491 ae44a02d67fb
child 1493 0dce3a3986a1
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
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/scripts/wrapper.c	Sat Aug 29 18:27:47 2009 +0200
     1.3 @@ -0,0 +1,128 @@
     1.4 +#include <limits.h>
     1.5 +#include <stdlib.h>
     1.6 +#include <stdio.h>
     1.7 +#include <string.h>
     1.8 +#include <sys/types.h>
     1.9 +#include <sys/stat.h>
    1.10 +#include <unistd.h>
    1.11 +#include <errno.h>
    1.12 +
    1.13 +
    1.14 +/* Needed for execve */
    1.15 +extern char **environ;
    1.16 +
    1.17 +int main( int argc,
    1.18 +          char** argv )
    1.19 +{
    1.20 +  char *fullname;   /* 'fullname' is used to store the absolute path to the
    1.21 +                       tool being executed; it serves as a base to compute
    1.22 +                       the realname of that tool, and the directory holding
    1.23 +                       our runtime libraries */
    1.24 +  char *realname;   /* 'realname' is the real name of the tool, that is what
    1.25 +                       the wrapper is currently impersonating */
    1.26 +  char *basedir;    /* 'libdir' contains our runtime libraries */
    1.27 +
    1.28 +  char *lastslash;  /* Temporary variables now */
    1.29 +  char *ldlibpath;
    1.30 +  size_t len;
    1.31 +  int execve_ret;
    1.32 +
    1.33 +  /* In case we have a relative or absolute pathname (ie. contains a slash),
    1.34 +   * then realpath wll work. But if the tool was found in the PATH, realpath
    1.35 +   * won't work, and we'll have to search ourselves.
    1.36 +   * This if{}else{} block allocates memory for fullname. */
    1.37 +  if( strchr( argv[0], '/' ) ) {
    1.38 +    fullname = (char*) malloc( PATH_MAX * sizeof(char) );
    1.39 +    if( ! realpath( argv[0], fullname ) ) {
    1.40 +      perror( "tool wrapper" );
    1.41 +      exit( 1 );
    1.42 +    }
    1.43 +  } else {
    1.44 +    char *path;
    1.45 +    char *mypath;
    1.46 +    char *colon;
    1.47 +    char *testname;
    1.48 +    struct stat st;
    1.49 +
    1.50 +    fullname = NULL;
    1.51 +    colon = mypath = path = strdup( getenv( "PATH" ) );
    1.52 +    while( colon ) {
    1.53 +      colon = strchr( mypath, ':' );
    1.54 +      if( colon ) {
    1.55 +        *colon = '\0';
    1.56 +      }
    1.57 +      testname = strdup( mypath );
    1.58 +      testname = (char*) realloc( testname,   strlen( testname )
    1.59 +                                            + strlen( argv[0] )
    1.60 +                                            + 2 * sizeof(char) );
    1.61 +      memset( testname + strlen( testname ),
    1.62 +              0,
    1.63 +              strlen( argv[0] ) + 2 * sizeof(char) );
    1.64 +      strcat( testname, "/" );
    1.65 +      strcat( testname, argv[0] );
    1.66 +      if( stat( testname, &st ) == 0 ) {
    1.67 +        /* OK, exists. Is it a regular file, or a
    1.68 +         * symlink, which the current user may execute? */
    1.69 +        if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) {
    1.70 +          fullname = strdup( testname );
    1.71 +          break;
    1.72 +        }
    1.73 +      }
    1.74 +      free( testname );
    1.75 +      mypath = colon + 1;
    1.76 +    }
    1.77 +    free( path );
    1.78 +    if( ! fullname ) {
    1.79 +      fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] );
    1.80 +      exit( 1 );
    1.81 +    }
    1.82 +  }
    1.83 +
    1.84 +  /* Duplicate my own name to add the 'dot' to tool name */
    1.85 +  realname = strdup( fullname );
    1.86 +  realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) );
    1.87 +  realname[ strlen( realname ) + 1 ] = '\0';
    1.88 +
    1.89 +  /* Add the dot after the last '/' */
    1.90 +  lastslash = strrchr( realname, '/' );
    1.91 +  memmove( lastslash + 1, lastslash, strlen( lastslash ) );
    1.92 +  *( lastslash + 1 ) = '.';
    1.93 +
    1.94 +  /* Compute the basedir of the tool */
    1.95 +  basedir = strdup( fullname );
    1.96 +  lastslash = strrchr( basedir, '/' );
    1.97 +  *lastslash = '\0';
    1.98 +  lastslash = strrchr( basedir, '/' );
    1.99 +  *lastslash = '\0';
   1.100 +
   1.101 +  /* Append '/lib' */
   1.102 +  len = strlen( basedir );
   1.103 +  basedir = (char*) realloc( basedir, len + 5 );
   1.104 +  *( basedir + len ) = '\0';
   1.105 +  strcat( basedir, "/lib" );
   1.106 +
   1.107 +  /* Now add the directory with our runtime libraries to the
   1.108 +     front of the library search path, LD_LIBRARY_PATH */
   1.109 +  ldlibpath = getenv( "LD_LIBRARY_PATH" );
   1.110 +  if( ldlibpath ) {
   1.111 +    basedir = (char*) realloc( basedir,   strlen( basedir )
   1.112 +                                        + strlen( ldlibpath )
   1.113 +                                        + 2 * sizeof(char) );
   1.114 +    strcat( basedir, ":" );
   1.115 +    strcat( basedir, ldlibpath );
   1.116 +  }
   1.117 +
   1.118 +  if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) {
   1.119 +    errno = ENOMEM;
   1.120 +    perror( "tool wrapper" );
   1.121 +    exit( 1 );
   1.122 +  }
   1.123 +
   1.124 +  /* Execute the real tool, now */
   1.125 +  execve_ret = execve( realname, argv, environ );
   1.126 +
   1.127 +  /* In case something went wrong above, print a
   1.128 +     diagnostic message, and exit with error code 1 */
   1.129 +  perror( "tool wrapper" );
   1.130 +  return 1;
   1.131 +}