chiark / gitweb /
Before try different approach since ldpreload does not work apparently
[jarrg-owen.git] / libjwrap.c
1 /**/
2
3 #define _GNU_SOURCE
4 #include <dlfcn.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdarg.h>
12
13 #define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
14 #define STDERRSTR_STRING(m) write(2,m,strlen(m))
15
16 #define QUIS "libjwrap"
17
18 typedef void anyfn_type(void);
19
20 static anyfn_type *find_any(const char *name) {
21   static const char *dlerr;
22   anyfn_type *kv;
23
24   kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
25   dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
26   STDERRSTR_CONST(QUIS ": error finding original version of ");
27   STDERRSTR_STRING(name);
28   STDERRSTR_CONST(": ");
29   STDERRSTR_STRING(dlerr);
30   STDERRSTR_CONST("\n");
31   errno= ENOSYS;
32   return 0;
33 }
34
35
36 #define REIMPLEMENTWRAP(FN, ARGS_DECL, ARGS_USE)        \
37                                                         \
38   typedef int FN##_type ARGS_DECL;                      \
39                                                         \
40   static FN##_type find_##FN, *old_##FN= find_##FN;     \
41                                                         \
42   static int find_##FN ARGS_DECL {                      \
43     anyfn_type *anyfn;                                  \
44     anyfn= find_any(# FN);  if (!anyfn) return -1;      \
45     old_##FN= (FN##_type*)anyfn;                        \
46     return old_##FN ARGS_USE;                           \
47   }                                                     \
48                                                         \
49   int FN ARGS_DECL
50
51
52
53 static const char javatail[]= "/bin/java";
54
55 REIMPLEMENTWRAP(execve,
56                 (const char *path, char *const oargv[], char *const envp[]),
57                 (path, oargv, envp)) {
58   int oargc;
59   for (oargc=0; oargv[oargc]; oargc++);
60
61   if (!strcmp(path,"/dev/jwrap/bypass")) {
62     //STDERRSTR_CONST(QUIS ": bypass\n");
63     int nargc= oargc-1;
64     char **nargv= malloc(sizeof(*nargv) * nargc);  if (!nargv) return -1;
65     nargv[0]= oargv[0];
66     memcpy(nargv+1, oargv+2, sizeof(*nargv) * nargc-1);
67     return old_execve(oargv[1], nargv, envp);
68   }
69
70   int pathlen= strlen(path);
71   if (!oargc ||
72       pathlen < (sizeof(javatail)-1) ||
73       strcmp(javatail, path + pathlen-(sizeof(javatail)-1))) {
74     //STDERRSTR_CONST(QUIS ": non-java\n");
75     return old_execve(path, oargv, envp);
76   }
77
78   //STDERRSTR_CONST(QUIS ": ours\n");
79
80   struct stat stab;
81   if (stat(path,&stab)) return -1;
82
83   int nargc= oargc+2;
84   char **nargv= malloc(sizeof(*nargv) * nargc);  if (!nargv) return -1;
85
86   const char *jwrap_script= getenv("JWRAP_SCRIPT");
87   if (!jwrap_script) {
88     STDERRSTR_CONST(QUIS ": no JWRAP_SCRIPT specified!\n");
89     errno= ENOENT;
90     return -1;
91   }
92
93   nargv[0]= (char*)jwrap_script;
94   nargv[1]= (char*)path;
95   memcpy(nargv+2, oargv, sizeof(*nargv) * (oargc+1));
96
97   old_execve(nargv[0], nargv, envp);
98   int e= errno;
99
100   const char *errstr= strerror(e);
101   STDERRSTR_CONST(QUIS ": failed to execute ");
102   STDERRSTR_STRING(jwrap_script);
103   STDERRSTR_CONST(": ");
104   STDERRSTR_STRING(errstr);
105   STDERRSTR_CONST("\n");
106   
107   errno= e;
108   return -1;
109 }
110
111 int execv(const char *path, char *const argv[]) {
112   return execve(path, argv, environ);
113 }
114
115
116 static int execvep(const char *path, char *const argv[], char *const envp[]) {
117   /* How tiresome.
118    * libc binds strongly to its own execve.
119    * That means we need to reimplement exec*p.
120    * (Also for some mysterious reason there is no standard execvep
121    *  and no standard execlep)
122    */
123   if (strchr(path,'/')) return execve(path,argv,envp);
124
125   int pathlen= strlen(path);
126   int buflen= 0;
127   char *buf= 0;
128
129   const char *searchpath= getenv("PATH");
130   for (;;) {
131     const char *colon= strchr(searchpath,':');
132     int entrylen= colon ? colon - searchpath : strlen(searchpath);
133     const char *try;
134     if (entrylen) {
135       try= path;
136     } else {
137       int trylen= entrylen + 1 + pathlen + 1;
138       if (trylen > buflen) {
139         free(buf);
140         buf= malloc(trylen);
141         if (!buf) return -1;
142         buflen= trylen;
143       }
144       memcpy(buf, searchpath, entrylen);
145       buf[entrylen]= '/';
146       strcpy(buf+entrylen+1, path);
147       try= buf;
148     }
149     execve(try, argv, envp);
150     if (errno != ENOENT)
151       return -1;
152   }
153   errno= ENOENT;
154   return -1;
155 }
156
157
158 static int execl_corev(int e, int p,
159                        const char *path, const char *arg0, va_list al) {
160   char *arg;
161   va_list countal;
162
163   va_copy(countal,al);
164   int argc=1;
165   while ((arg= va_arg(countal, char*)))
166     argc++;
167   va_end(countal);
168
169   char **argv= malloc(sizeof(*argv) * (argc+1));
170   argc=0;
171   argv[argc++]= (char*)arg0;
172   while ((arg= va_arg(al, char*)))
173     argv[argc++]= arg;
174   argv[argc]= 0;
175
176   char **envp= e ? va_arg(al, char**) : environ;
177
178   if (p) return execvep(path, argv, envp);
179   else return execve(path, argv, envp);
180 }   
181
182
183 #define REIMPLEMENTLCOREV(FN,E,P)                       \
184   int FN(const char *path, const char *arg, ...) {      \
185     va_list al;                                         \
186     va_start(al,arg);                                   \
187     execl_corev(E,P,path,arg,al);                       \
188     va_end(al);                                         \
189     return -1;                                          \
190   }
191
192 REIMPLEMENTLCOREV( execl,  0,0 )
193 REIMPLEMENTLCOREV( execle, 1,0 )
194 REIMPLEMENTLCOREV( execlp, 0,1 )