scripts/wrapper.c
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sun Jan 17 23:06:02 2010 +0100 (2010-01-17)
changeset 1740 c57458bb354d
parent 1492 b97f8fa54d67
child 1964 f02cfced8f55
child 1998 110ba570a70a
permissions -rw-r--r--
configure: do not require hg when configuring in an hg clone

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