X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=306b70e5a4b09bfe2388ec0633f194d0049314bc;hp=f156603af8ac180900fe074b1e7932947e3d1eff;hb=b11e7c6c29f2b5f7b0828bf93eb741c4a30ec411;hpb=6b824fa9a85f2f58fcb938ea5924df0c73cea43c diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index f156603..306b70e 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -1,12 +1,10 @@ // Copyright 2000-2005 the Contributors, as shown in the revision logs. -// Licensed under the Apache Public Source License 2.0 ("the License"). +// Licensed under the Apache License 2.0 ("the License"). // You may not use this file except in compliance with the License. package org.ibex.nestedvm; import org.ibex.nestedvm.util.*; -// HACK: This is ugly, this stuff needs to be in org.ibex.util or something -import org.ibex.classgen.util.Sort; import java.io.*; import java.util.*; import java.net.*; @@ -46,28 +44,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(!exec) { gs = defaultGS; String userdir = Platform.getProperty("user.dir"); - String nvroot = Platform.getProperty("nestedvm.root"); - cwd = ""; - if(userdir != null && nvroot == null) { - if(userdir.startsWith("/") && File.separatorChar == '/') { - cwd = userdir.substring(1); - } else { - Vector vec = new Vector(); - File root = HostFS.hostRootDir(); - String s = new File(userdir).getAbsolutePath(); - File d = new File(s); - System.err.println(s); - System.err.println(d); - while(!d.equals(root)) { - System.err.println("Got " + d.getName()); - vec.addElement(d.getName()); - if((s = d.getParent()) == null) break; - d = new File(s); - } - if(s != null) - for(int i=vec.size()-1;i>=0;i--) cwd += (String) vec.elementAt(i) + (i==0?"":"/"); - } - } + cwd = userdir == null ? null : gs.mapHostPath(userdir); + if(cwd == null) cwd = "/"; + cwd = cwd.substring(1); } } @@ -93,13 +72,16 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } String[] createEnv(String[] extra) { - String[] defaults = new String[6]; + String[] defaults = new String[7]; int n=0; if(extra == null) extra = new String[0]; + String tmp; if(!envHas("USER",extra) && Platform.getProperty("user.name") != null) defaults[n++] = "USER=" + Platform.getProperty("user.name"); - if(!envHas("HOME",extra) && Platform.getProperty("user.home") != null) - defaults[n++] = "HOME=" + Platform.getProperty("user.home"); + if(!envHas("HOME",extra) && (tmp=Platform.getProperty("user.home")) != null && (tmp=gs.mapHostPath(tmp)) != null) + defaults[n++] = "HOME=" + tmp; + if(!envHas("TMPDIR",extra) && (tmp=Platform.getProperty("java.io.tmpdir")) != null && (tmp=gs.mapHostPath(tmp)) != null) + defaults[n++] = "TMPDIR=" + tmp; if(!envHas("SHELL",extra)) defaults[n++] = "SHELL=/bin/sh"; if(!envHas("TERM",extra) && !win32Hacks) defaults[n++] = "TERM=vt100"; if(!envHas("TZ",extra)) defaults[n++] = "TZ=" + posixTZ(); @@ -169,23 +151,51 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case SYS_select: return sys_select(a,b,c,d,e); case SYS_access: return sys_access(a,b); case SYS_realpath: return sys_realpath(a,b); - + case SYS_chown: return sys_chown(a,b,c); + case SYS_lchown: return sys_chown(a,b,c); + case SYS_fchown: return sys_fchown(a,b,c); + case SYS_chmod: return sys_chmod(a,b,c); + case SYS_fchmod: return sys_fchmod(a,b,c); + case SYS_fcntl: return sys_fcntl_lock(a,b,c); + case SYS_umask: return sys_umask(a); + default: return super._syscall(syscall,a,b,c,d,e,f); } } FD _open(String path, int flags, int mode) throws ErrnoException { - return gs.open(this,normalizePath(path),flags,mode); + path = normalizePath(path); + FD fd = gs.open(this,path,flags,mode); + if (fd != null && path != null) fd.setNormalizedPath(path); + return fd; } private int sys_getppid() { return parent == null ? 1 : parent.pid; } + private int sys_chown(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_lchown(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_fchown(int fd, int uid, int gid) { + return 0; + } + private int sys_chmod(int fileAddr, int uid, int gid) { + return 0; + } + private int sys_fchmod(int fd, int uid, int gid) { + return 0; + } + private int sys_umask(int mask) { + return 0; + } - private int sys_access(int cstring, int mode) { + private int sys_access(int cstring, int mode) throws ErrnoException, ReadFaultException { // FEATURE: sys_access - return 0; + return gs.stat(this,cstring(cstring)) == null ? -ENOENT : 0; } private int sys_realpath(int inAddr, int outAddr) throws FaultException { @@ -387,7 +397,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { static { Method m; try { - m = Class.forName("org.ibex.nestedvm.RuntimeCompiler").getMethod("compile",new Class[]{Seekable.class,String.class}); + m = Class.forName("org.ibex.nestedvm.RuntimeCompiler").getMethod("compile",new Class[]{Seekable.class,String.class,String.class}); } catch(NoSuchMethodException e) { m = null; } catch(ClassNotFoundException e) { @@ -396,14 +406,14 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { runtimeCompilerCompile = m; } - public Class runtimeCompile(Seekable s) throws IOException { + public Class runtimeCompile(Seekable s, String sourceName) throws IOException { if(runtimeCompilerCompile == null) { if(STDERR_DIAG) System.err.println("WARNING: Exec attempted but RuntimeCompiler not found!"); return null; } try { - return (Class) runtimeCompilerCompile.invoke(null,new Object[]{s,"unixruntime"}); + return (Class) runtimeCompilerCompile.invoke(null,new Object[]{s,"unixruntime,maxinsnpermethod=256,lessconstants",sourceName}); } catch(IllegalAccessException e) { e.printStackTrace(); return null; @@ -463,7 +473,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(n < 4) s.tryReadFully(buf,n,4-n); if(buf[1] != 'E' || buf[2] != 'L' || buf[3] != 'F') return -ENOEXEC; s.seek(0); - Class c = runtimeCompile(s); + 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); @@ -482,13 +494,16 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(p == buf.length) break OUTER; n = s.read(buf,p,buf.length-p); } - int arg; - for(arg=2;arg= OPEN_MAX) return -EBADFD; + if(fds[fdn] == null) return -EBADFD; + FD fd = fds[fdn]; + + if (arg == 0) return -EINVAL; + int word = memRead(arg); + int l_start = memRead(arg+4); + int l_len = memRead(arg+8); + int l_type = word>>16; + int l_whence = word&0x00ff; + + Seekable.Lock[] locks = gs.locks; + Seekable s = fd.seekable(); + if (s == null) return -EINVAL; + + try { + + switch (l_whence) { + case SEEK_SET: break; + case SEEK_CUR: l_start += s.pos(); break; + case SEEK_END: l_start += s.length(); break; + default: return -1; + } + + if (cmd == F_GETLK) { + // The simple Java file locking below will happily return + // a lock that overlaps one already held by the JVM. Thus + // we must check over all the locks held by other Runtimes + for (int i=0; i < locks.length; i++) { + if (locks[i] == null || !s.equals(locks[i].seekable())) + continue; + if (!locks[i].overlaps(l_start, l_len)) + continue; + if (locks[i].getOwner() == this) + continue; + if (locks[i].isShared() && l_type == F_RDLCK) + continue; + + // overlapping lock held by another process + return 0; + } + + // check if an area is lockable by attempting to obtain a lock + Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK); + + if (lock != null) { // no lock exists + memWrite(arg, SEEK_SET|(F_UNLCK<<16)); + lock.release(); + } + + return 0; + } + + // now processing F_SETLK + if (cmd != F_SETLK) return -EINVAL; + + if (l_type == F_UNLCK) { + // release all locks that fall within the boundaries given + for (int i=0; i < locks.length; i++) { + if (locks[i] == null || !s.equals(locks[i].seekable())) + continue; + if (locks[i].getOwner() != this) continue; + + int pos = (int)locks[i].position(); + if (pos < l_start) continue; + if (l_start != 0 && l_len != 0) // start/len 0 means unlock all + if (pos + locks[i].size() > l_start + l_len) + continue; + + locks[i].release(); + locks[i] = null; + } + return 0; + + } else if (l_type == F_RDLCK || l_type == F_WRLCK) { + // first see if a lock already exists + for (int i=0; i < locks.length; i++) { + if (locks[i] == null || !s.equals(locks[i].seekable())) + continue; + + if (locks[i].getOwner() == this) { + // if this Runtime owns an overlapping lock work with it + if (locks[i].contained(l_start, l_len)) { + locks[i].release(); + locks[i] = null; + } else if (locks[i].contains(l_start, l_len)) { + if (locks[i].isShared() == (l_type == F_RDLCK)) { + // return this more general lock + memWrite(arg+4, (int)locks[i].position()); + memWrite(arg+8, (int)locks[i].size()); + return 0; + } else { + locks[i].release(); + locks[i] = null; + } + } + } else { + // if another Runtime has an lock and it is exclusive or + // we want an exclusive lock then fail + if (locks[i].overlaps(l_start, l_len) + && (!locks[i].isShared() || l_type == F_WRLCK)) + return -EAGAIN; + } + } + + // create the lock + Seekable.Lock lock = s.lock(l_start, l_len, l_type == F_RDLCK); + if (lock == null) return -EAGAIN; + lock.setOwner(this); + + int i; + for (i=0; i < locks.length; i++) + if (locks[i] == null) break; + if (i == locks.length) return -ENOLCK; + locks[i] = lock; + return 0; + + } else { + return -EINVAL; + } + + } catch (IOException e) { throw new RuntimeException(e); } + } + static class SocketFD extends FD { public static final int TYPE_STREAM = 0; public static final int TYPE_DGRAM = 1; @@ -1146,6 +1327,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { final UnixRuntime[] tasks; int nextPID = 1; + /** Table of all current file locks held by this process. */ + Seekable.Lock[] locks = new Seekable.Lock[16]; + private MP[] mps = new MP[0]; private FS root; @@ -1154,9 +1338,62 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public GlobalState(int maxProcs, boolean defaultMounts) { tasks = new UnixRuntime[maxProcs+1]; if(defaultMounts) { - addMount("/",new HostFS()); + File root = null; + if(Platform.getProperty("nestedvm.root") != null) { + root = new File(Platform.getProperty("nestedvm.root")); + if(!root.isDirectory()) throw new IllegalArgumentException("nestedvm.root is not a directory"); + } else { + String cwd = Platform.getProperty("user.dir"); + root = Platform.getRoot(new File(cwd != null ? cwd : ".")); + } + + addMount("/",new HostFS(root)); + + if(Platform.getProperty("nestedvm.root") == null) { + File[] roots = Platform.listRoots(); + for(int i=0;i=0;i--) { + FS fs = i == mps.length ? root : mps[i].fs; + String path = i == mps.length ? "" : mps[i].path; + if(!(fs instanceof HostFS)) continue; + File fsroot = ((HostFS)fs).getRoot(); + if(!fsroot.isAbsolute()) fsroot = new File(fsroot.getAbsolutePath()); + if(f.getPath().startsWith(fsroot.getPath())) { + char sep = File.separatorChar; + String child = f.getPath().substring(fsroot.getPath().length()); + if(sep != '/') { + char[] child_ = child.toCharArray(); + for(int j=0;j 0 && out[outp-1] == '/') outp--; //System.err.println("normalize: " + path + " -> " + new String(out,0,outp) + " (cwd: " + cwd + ")"); - return new String(out,0,outp); + int outStart = out[0] == '/' ? 1 : 0; + return new String(out,outStart,outp - outStart); } FStat hostFStat(final File f, Object data) { @@ -1364,23 +1602,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { protected File root; public File getRoot() { return root; } - static File hostRootDir() { - if(Platform.getProperty("nestedvm.root") != null) { - File f = new File(Platform.getProperty("nestedvm.root")); - if(f.isDirectory()) return f; - // fall through to case below - } - String cwd = Platform.getProperty("user.dir"); - File f = new File(cwd != null ? cwd : "."); - if(!f.exists()) throw new Error("Couldn't get File for cwd"); - f = new File(f.getAbsolutePath()); - while(f.getParent() != null) f = new File(f.getParent()); - // This works around a bug in some versions of ClassPath - if(f.getPath().length() == 0) f = new File("/"); - return f; - } - - private File hostFile(String path) { + protected File hostFile(String path) { char sep = File.separatorChar; if(sep != '/') { char buf[] = path.toCharArray(); @@ -1394,11 +1616,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return new File(root,path); } - public HostFS() { this(hostRootDir()); } public HostFS(String root) { this(new File(root)); } public HostFS(File root) { this.root = root; } - public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { final File f = hostFile(path); return r.hostFSOpen(f,flags,mode,this); @@ -1408,7 +1628,21 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { File f = hostFile(path); if(r.sm != null && !r.sm.allowUnlink(f)) throw new ErrnoException(EPERM); if(!f.exists()) throw new ErrnoException(ENOENT); - if(!f.delete()) throw new ErrnoException(EPERM); + if(!f.delete()) { + // Can't delete file immediately, so mark for + // delete on close all matching FDs + boolean marked = false; + for(int i=0;i 'z' || path.charAt(1) != '/') + return null; + + path = drive + ":" + path.substring(1).replace('/', '\\'); + return new File(path); + } + + public CygdriveFS() { super("/"); } + } private static void putInt(byte[] buf, int off, int n) { buf[off+0] = (byte)((n>>>24)&0xff); @@ -1631,5 +1882,55 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { throw new ErrnoException(EROFS); } public void unlink(UnixRuntime r, String path) throws ErrnoException { throw new ErrnoException(EROFS); } - } + } + + + public static class ResourceFS extends FS { + final InodeCache inodes = new InodeCache(500); + + public FStat lstat(UnixRuntime r, String path) throws ErrnoException { return stat(r,path); } + public void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { throw new ErrnoException(EROFS); } + public void unlink(UnixRuntime r, String path) throws ErrnoException { throw new ErrnoException(EROFS); } + + FStat connFStat(final URLConnection conn) { + return new FStat() { + public int type() { return S_IFREG; } + public int nlink() { return 1; } + public int mode() { return 0444; } + public int size() { return conn.getContentLength(); } + public int mtime() { return (int)(conn.getDate() / 1000); } + public int inode() { return inodes.get(conn.getURL().toString()); } + public int dev() { return devno; } + }; + } + + public FStat stat(UnixRuntime r, String path) throws ErrnoException { + URL url = r.getClass().getResource("/" + path); + if(url == null) return null; + try { + return connFStat(url.openConnection()); + } catch(IOException e) { + throw new ErrnoException(EIO); + } + } + + public FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { + if((flags & ~3) != 0) { + if(STDERR_DIAG) + System.err.println("WARNING: Unsupported flags passed to ResourceFS.open(\"" + path + "\"): " + toHex(flags & ~3)); + throw new ErrnoException(ENOTSUP); + } + if((flags&3) != RD_ONLY) throw new ErrnoException(EROFS); + URL url = r.getClass().getResource("/" + path); + if(url == null) return null; + try { + final URLConnection conn = url.openConnection(); + Seekable.InputStream si = new Seekable.InputStream(conn.getInputStream()); + return new SeekableFD(si,flags) { protected FStat _fstat() { return connFStat(conn); } }; + } catch(FileNotFoundException e) { + if(e.getMessage() != null && e.getMessage().indexOf("Permission denied") >= 0) throw new ErrnoException(EACCES); + return null; + } catch(IOException e) { throw new ErrnoException(EIO); } + } + } }