scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Mar 28 01:05:18 2011 +0200 (2011-03-28)
changeset 2362 0888065f8c4d
parent 1964 f02cfced8f55
permissions -rw-r--r--
cc/gcc: cleanup the _or_later logic

So far, we've had a version always select appropriate _or_later option,
which in turn would select all previous _or_later options.

Because the dependencies on companion libs were cumulative, that was
working OK. But the upcoming 4.6 will no longer depend on libelf, so
we can't keep the cumulative scheme we've been using so far.

Have each release family select the corresponding dependencies, instead
of relying on selecting previous _or_later.

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