scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat Aug 29 18:27:47 2009 +0200 (2009-08-29)
changeset 1492 b97f8fa54d67
child 1504 4e8dd617a1ca
permissions -rw-r--r--
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
     1 #include <limits.h>
     2 #include <stdlib.h>
     3 #include <stdio.h>
     4 #include <string.h>
     5 #include <sys/types.h>
     6 #include <sys/stat.h>
     7 #include <unistd.h>
     8 #include <errno.h>
     9 
    10 
    11 /* Needed for execve */
    12 extern char **environ;
    13 
    14 int main( int argc,
    15           char** argv )
    16 {
    17   char *fullname;   /* 'fullname' is used to store the absolute path to the
    18                        tool being executed; it serves as a base to compute
    19                        the realname of that tool, and the directory holding
    20                        our runtime libraries */
    21   char *realname;   /* 'realname' is the real name of the tool, that is what
    22                        the wrapper is currently impersonating */
    23   char *basedir;    /* 'libdir' contains our runtime libraries */
    24 
    25   char *lastslash;  /* Temporary variables now */
    26   char *ldlibpath;
    27   size_t len;
    28   int execve_ret;
    29 
    30   /* In case we have a relative or absolute pathname (ie. contains a slash),
    31    * then realpath wll work. But if the tool was found in the PATH, realpath
    32    * won't work, and we'll have to search ourselves.
    33    * This if{}else{} block allocates memory for fullname. */
    34   if( strchr( argv[0], '/' ) ) {
    35     fullname = (char*) malloc( PATH_MAX * sizeof(char) );
    36     if( ! realpath( argv[0], fullname ) ) {
    37       perror( "tool wrapper" );
    38       exit( 1 );
    39     }
    40   } else {
    41     char *path;
    42     char *mypath;
    43     char *colon;
    44     char *testname;
    45     struct stat st;
    46 
    47     fullname = NULL;
    48     colon = mypath = path = strdup( getenv( "PATH" ) );
    49     while( colon ) {
    50       colon = strchr( mypath, ':' );
    51       if( colon ) {
    52         *colon = '\0';
    53       }
    54       testname = strdup( mypath );
    55       testname = (char*) realloc( testname,   strlen( testname )
    56                                             + strlen( argv[0] )
    57                                             + 2 * sizeof(char) );
    58       memset( testname + strlen( testname ),
    59               0,
    60               strlen( argv[0] ) + 2 * sizeof(char) );
    61       strcat( testname, "/" );
    62       strcat( testname, argv[0] );
    63       if( stat( testname, &st ) == 0 ) {
    64         /* OK, exists. Is it a regular file, or a
    65          * symlink, which the current user may execute? */
    66         if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) {
    67           fullname = strdup( testname );
    68           break;
    69         }
    70       }
    71       free( testname );
    72       mypath = colon + 1;
    73     }
    74     free( path );
    75     if( ! fullname ) {
    76       fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] );
    77       exit( 1 );
    78     }
    79   }
    80 
    81   /* Duplicate my own name to add the 'dot' to tool name */
    82   realname = strdup( fullname );
    83   realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) );
    84   realname[ strlen( realname ) + 1 ] = '\0';
    85 
    86   /* Add the dot after the last '/' */
    87   lastslash = strrchr( realname, '/' );
    88   memmove( lastslash + 1, lastslash, strlen( lastslash ) );
    89   *( lastslash + 1 ) = '.';
    90 
    91   /* Compute the basedir of the tool */
    92   basedir = strdup( fullname );
    93   lastslash = strrchr( basedir, '/' );
    94   *lastslash = '\0';
    95   lastslash = strrchr( basedir, '/' );
    96   *lastslash = '\0';
    97 
    98   /* Append '/lib' */
    99   len = strlen( basedir );
   100   basedir = (char*) realloc( basedir, len + 5 );
   101   *( basedir + len ) = '\0';
   102   strcat( basedir, "/lib" );
   103 
   104   /* Now add the directory with our runtime libraries to the
   105      front of the library search path, LD_LIBRARY_PATH */
   106   ldlibpath = getenv( "LD_LIBRARY_PATH" );
   107   if( ldlibpath ) {
   108     basedir = (char*) realloc( basedir,   strlen( basedir )
   109                                         + strlen( ldlibpath )
   110                                         + 2 * sizeof(char) );
   111     strcat( basedir, ":" );
   112     strcat( basedir, ldlibpath );
   113   }
   114 
   115   if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) {
   116     errno = ENOMEM;
   117     perror( "tool wrapper" );
   118     exit( 1 );
   119   }
   120 
   121   /* Execute the real tool, now */
   122   execve_ret = execve( realname, argv, environ );
   123 
   124   /* In case something went wrong above, print a
   125      diagnostic message, and exit with error code 1 */
   126   perror( "tool wrapper" );
   127   return 1;
   128 }