scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Wed Feb 17 23:41:17 2010 +0100 (2010-02-17)
changeset 1811 35cf5e2f110a
parent 1492 b97f8fa54d67
child 1964 f02cfced8f55
child 1998 110ba570a70a
permissions -rw-r--r--
comp-libs: make libelf a companion library

When gcc-4.5 is out, it will require libelf. So better make it a
companion library now rather than postponing the ineluctable.
     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   /* Avoid the warning-treated-as-error: "error: unused parameter 'argc'" */
    31   len = argc;
    32 
    33   /* In case we have a relative or absolute pathname (ie. contains a slash),
    34    * then realpath wll work. But if the tool was found in the PATH, realpath
    35    * won't work, and we'll have to search ourselves.
    36    * This if{}else{} block allocates memory for fullname. */
    37   if( strchr( argv[0], '/' ) ) {
    38     fullname = (char*) malloc( PATH_MAX * sizeof(char) );
    39     if( ! realpath( argv[0], fullname ) ) {
    40       perror( "tool wrapper" );
    41       exit( 1 );
    42     }
    43   } else {
    44     char *path;
    45     char *mypath;
    46     char *colon;
    47     char *testname;
    48     struct stat st;
    49 
    50     fullname = NULL;
    51     colon = mypath = path = strdup( getenv( "PATH" ) );
    52     while( colon ) {
    53       colon = strchr( mypath, ':' );
    54       if( colon ) {
    55         *colon = '\0';
    56       }
    57       testname = strdup( mypath );
    58       testname = (char*) realloc( testname,   strlen( testname )
    59                                             + strlen( argv[0] )
    60                                             + 2 * sizeof(char) );
    61       memset( testname + strlen( testname ),
    62               0,
    63               strlen( argv[0] ) + 2 * sizeof(char) );
    64       strcat( testname, "/" );
    65       strcat( testname, argv[0] );
    66       if( stat( testname, &st ) == 0 ) {
    67         /* OK, exists. Is it a regular file, or a
    68          * symlink, which the current user may execute? */
    69         if( S_ISREG( st.st_mode ) && ! access( testname, X_OK || R_OK ) ) {
    70           fullname = strdup( testname );
    71           break;
    72         }
    73       }
    74       free( testname );
    75       mypath = colon + 1;
    76     }
    77     free( path );
    78     if( ! fullname ) {
    79       fprintf( stderr, "tool wrapper: %s: command not found\n", argv[0] );
    80       exit( 1 );
    81     }
    82   }
    83 
    84   /* Duplicate my own name to add the 'dot' to tool name */
    85   realname = strdup( fullname );
    86   realname = (char*) realloc( realname, strlen( realname) + 2 * sizeof(char) );
    87   realname[ strlen( realname ) + 1 ] = '\0';
    88 
    89   /* Add the dot after the last '/' */
    90   lastslash = strrchr( realname, '/' );
    91   memmove( lastslash + 1, lastslash, strlen( lastslash ) );
    92   *( lastslash + 1 ) = '.';
    93 
    94   /* Compute the basedir of the tool */
    95   basedir = strdup( fullname );
    96   lastslash = strrchr( basedir, '/' );
    97   *lastslash = '\0';
    98   lastslash = strrchr( basedir, '/' );
    99   *lastslash = '\0';
   100 
   101   /* Append '/lib' */
   102   len = strlen( basedir );
   103   basedir = (char*) realloc( basedir, len + 5 );
   104   *( basedir + len ) = '\0';
   105   strcat( basedir, "/lib" );
   106 
   107   /* Now add the directory with our runtime libraries to the
   108      front of the library search path, LD_LIBRARY_PATH */
   109   ldlibpath = getenv( "LD_LIBRARY_PATH" );
   110   if( ldlibpath ) {
   111     basedir = (char*) realloc( basedir,   strlen( basedir )
   112                                         + strlen( ldlibpath )
   113                                         + 2 * sizeof(char) );
   114     strcat( basedir, ":" );
   115     strcat( basedir, ldlibpath );
   116   }
   117 
   118   if( setenv( "LD_LIBRARY_PATH", basedir, 1 ) ) {
   119     errno = ENOMEM;
   120     perror( "tool wrapper" );
   121     exit( 1 );
   122   }
   123 
   124   /* Execute the real tool, now */
   125   execve_ret = execve( realname, argv, environ );
   126 
   127   /* In case something went wrong above, print a
   128      diagnostic message, and exit with error code 1 */
   129   perror( "tool wrapper" );
   130   return 1;
   131 }