scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat Sep 24 21:47:28 2011 +0200 (2011-09-24)
branch1.10
changeset 2678 564d1f3a849b
parent 1964 f02cfced8f55
permissions -rw-r--r--
1.10: close branch

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 }