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 |
}
|