+ //System.err.println("Cache was out of date");
+ gs.execCache.remove(path);
+ }
+
+ FD fd = gs.open(this,path,RD_ONLY,0);
+ if(fd == null) throw new ErrnoException(ENOENT);
+ Seekable s = fd.seekable();
+ if(s == null) throw new ErrnoException(EACCES);
+
+ byte[] buf = new byte[4096];
+
+ try {
+ int n = s.read(buf,0,buf.length);
+ if(n == -1) throw new ErrnoException(ENOEXEC);
+
+ switch(buf[0]) {
+ case '\177': // possible ELF
+ if(n < 4) s.tryReadFully(buf,n,4-n);
+ if(buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') return -ENOEXEC;
+ s.seek(0);
+ if(STDERR_DIAG) System.err.println("Running RuntimeCompiler for " + path);
+ Class c = runtimeCompile(s,path);
+ if(STDERR_DIAG) System.err.println("RuntimeCompiler finished for " + path);
+ if(c == null) throw new ErrnoException(ENOEXEC);
+ gs.execCache.put(path,new GlobalState.CacheEnt(mtime,size,c));
+ return execClass(c,argv,envp);
+ case '#':
+ if(n == 1) {
+ int n2 = s.read(buf,1,buf.length-1);
+ if(n2 == -1) return -ENOEXEC;
+ n += n2;
+ }
+ if(buf[1] != '!') return -ENOEXEC;
+ int p = 2;
+ n -= 2;
+ OUTER: for(;;) {
+ for(int i=p;i<p+n;i++) if(buf[i] == '\n') { p = i; break OUTER; }
+ p += n;
+ if(p == buf.length) break OUTER;
+ n = s.read(buf,p,buf.length-p);
+ }
+ int cmdStart = 2;
+ for(;cmdStart<p;cmdStart++) if(buf[cmdStart]!=' ') break;
+ if(cmdStart == p) throw new ErrnoException(ENOEXEC);
+ int argStart = cmdStart;
+ for(;argStart<p;argStart++) if(buf[argStart] == ' ') break;
+ int cmdEnd = argStart;
+ while(argStart < p && buf[argStart] == ' ') argStart++;
+ String[] command = new String[] {
+ new String(buf,cmdStart,cmdEnd-cmdStart),
+ argStart < p ? new String(buf,argStart,p-argStart) : null
+ };
+ gs.execCache.put(path,new GlobalState.CacheEnt(mtime,size,command));
+ return execScript(path,command,argv,envp);
+ default:
+ return -ENOEXEC;
+ }
+ } catch(IOException e) {
+ return -EIO;
+ } finally {
+ fd.close();
+ }
+ }
+
+ public int execScript(String path, String[] command, String[] argv, String[] envp) throws ErrnoException {
+ String[] newArgv = new String[argv.length-1 + (command[1] != null ? 3 : 2)];
+ int p = command[0].lastIndexOf('/');
+ newArgv[0] = p == -1 ? command[0] : command[0].substring(p+1);
+ newArgv[1] = "/" + path;
+ p = 2;
+ if(command[1] != null) newArgv[p++] = command[1];
+ for(int i=1;i<argv.length;i++) newArgv[p++] = argv[i];
+ if(p != newArgv.length) throw new Error("p != newArgv.length");
+ System.err.println("Execing: " + command[0]);
+ for(int i=0;i<newArgv.length;i++) System.err.println("execing [" + i + "] " + newArgv[i]);
+ return exec(command[0],newArgv,envp);
+ }
+
+ public int execClass(Class c,String[] argv, String[] envp) {
+ try {
+ UnixRuntime r = (UnixRuntime) c.getDeclaredConstructor(new Class[]{Boolean.TYPE}).newInstance(new Object[]{Boolean.TRUE});
+ return exec(r,argv,envp);
+ } catch(Exception e) {
+ e.printStackTrace();
+ return -ENOEXEC;