chiark / gitweb /
Sort of works ...
[jarrg-owen.git] / libjwrap.c
diff --git a/libjwrap.c b/libjwrap.c
new file mode 100644 (file)
index 0000000..b74a99a
--- /dev/null
@@ -0,0 +1,100 @@
+/**/
+
+#define _GNU_SOURCE
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define STDERRSTR_CONST(m) write(2,m,sizeof(m)-1)
+#define STDERRSTR_STRING(m) write(2,m,strlen(m))
+
+#define QUIS "libjwrap"
+
+typedef void anyfn_type(void);
+typedef int
+execvefn_type(const char *path, char *const argv[], char *const envp[]);
+
+static execvefn_type find_execve, *old_execve= find_execve;
+
+static anyfn_type *find_any(const char *name) {
+  static const char *dlerr;
+  anyfn_type *kv;
+
+  kv= dlsym(RTLD_NEXT,name); if (kv) return kv;
+  dlerr= dlerror(); if (!dlerr) dlerr= "dlsym() failed for no reason";
+  STDERRSTR_CONST(QUIS ": error finding original version of ");
+  STDERRSTR_STRING(name);
+  STDERRSTR_CONST(": ");
+  STDERRSTR_STRING(dlerr);
+  STDERRSTR_CONST("\n");
+  errno= ENOSYS;
+  return 0;
+}
+
+static int find_execve(const char *path,
+                      char *const argv[], char *const envp[]) {
+  anyfn_type *anyfn;
+  anyfn= find_any("execve"); if (!anyfn) return -1;
+  old_execve= (execvefn_type*)anyfn;
+  return old_execve(path, argv, envp);
+}
+
+static const char javatail[]= "/bin/java";
+
+int execve(const char *path, char *const oargv[], char *const envp[]) {
+  int oargc;
+  for (oargc=0; oargv[oargc]; oargc++);
+
+  if (!strcmp(path,"/dev/jwrap/bypass")) {
+    //STDERRSTR_CONST(QUIS ": bypass\n");
+    int nargc= oargc-1;
+    char **nargv= malloc(sizeof(*nargv) * nargc);  if (!nargv) return -1;
+    nargv[0]= oargv[0];
+    memcpy(nargv+1, oargv+2, sizeof(*nargv) * nargc-1);
+    return old_execve(oargv[1], nargv, envp);
+  }
+
+  int pathlen= strlen(path);
+  if (!oargc ||
+      pathlen < (sizeof(javatail)-1) ||
+      strcmp(javatail, path + pathlen-(sizeof(javatail)-1))) {
+    //STDERRSTR_CONST(QUIS ": non-java\n");
+    return old_execve(path, oargv, envp);
+  }
+
+  //STDERRSTR_CONST(QUIS ": ours\n");
+
+  struct stat stab;
+  if (stat(path,&stab)) return -1;
+
+  int nargc= oargc+2;
+  char **nargv= malloc(sizeof(*nargv) * nargc);  if (!nargv) return -1;
+
+  const char *jwrap_script= getenv("JWRAP_SCRIPT");
+  if (!jwrap_script) {
+    STDERRSTR_CONST(QUIS ": no JWRAP_SCRIPT specified!\n");
+    errno= ENOENT;
+    return -1;
+  }
+
+  nargv[0]= (char*)jwrap_script;
+  nargv[1]= (char*)path;
+  memcpy(nargv+2, oargv, sizeof(*nargv) * (oargc+1));
+
+  old_execve(nargv[0], nargv, envp);
+  int e= errno;
+
+  const char *errstr= strerror(e);
+  STDERRSTR_CONST(QUIS ": failed to execute ");
+  STDERRSTR_STRING(jwrap_script);
+  STDERRSTR_CONST(": ");
+  STDERRSTR_STRING(errstr);
+  STDERRSTR_CONST("\n");
+  
+  errno= e;
+  return -1;
+}