scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Mon Mar 29 00:15:32 2010 +0200 (2010-03-29)
changeset 1864 758d5137fe87
parent 1492 b97f8fa54d67
child 1964 f02cfced8f55
child 1998 110ba570a70a
permissions -rw-r--r--
scripts/populate: optimise search loop

Curently, populate will iterate over all ELF (shared objects|executables)
to look for missing NEEDED DSOs, adding to the list at every iterations
of the search loop.

Instead of looking again at previously handled ELF files, recursively
resolve every ELf files.

Also, in case there are a whole lot of files (more than the shell can
accept as arguments list, or creating a command line longer than the
shell can cope with), use a temporary file with the list of files
to search for missing dependencies.
     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 }