X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=151699f8c4c35c20b955291830371011c752070e;hp=8aa5dc77ce9feaf9228804dbb81c2e51b059946f;hb=7e1e0dc49707b777e71e69c23c0a48e0a2665a4b;hpb=ad692a248f2ed9412db5b313b85fd8365488017f diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index 8aa5dc7..151699f 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -4,22 +4,18 @@ import org.ibex.nestedvm.util.*; import java.io.*; import java.util.*; -// FIXME: Fix readdir in support_aux.c -// FIXME: Make plain old "mips-unknown-elf-gcc -o foo foo.c" work (modify spec file or whatever) - -// FEATURE: Remove System.{out,err}.printlns and throw Errors where applicable - -// FIXME: BusyBox's ASH doesn't like \r\n at the end of lines -// is ash just broken or are many apps like this? if so workaround in nestedvm - public abstract class UnixRuntime extends Runtime implements Cloneable { /** The pid of this "process" */ private int pid; private UnixRuntime parent; public final int getPid() { return pid; } - private static final GlobalState defaultGD = new GlobalState(); - private GlobalState gd = defaultGD; + private static final GlobalState defaultGS = new GlobalState(); + private GlobalState gs = defaultGS; + public void setGlobalState(GlobalState gs) { + if(state != STOPPED) throw new IllegalStateException("can't change GlobalState when running"); + this.gs = gs; + } /** proceses' current working directory - absolute path WITHOUT leading slash "" = root, "bin" = /bin "usr/bin" = /usr/bin */ @@ -37,7 +33,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { // FEATURE: Do the proper mangling for non-unix hosts String userdir = getSystemProperty("user.dir"); - cwd = userdir != null && userdir.startsWith("/") && File.separatorChar == '/' ? userdir.substring(1) : ""; + cwd = + userdir != null && userdir.startsWith("/") && File.separatorChar == '/' && HostFS.hostRootDir().getParent() == null + ? userdir.substring(1) : ""; } // NOTE: getDisplayName() is a Java2 function @@ -68,7 +66,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(extra == null) extra = new String[0]; if(!envHas("USER",extra) && getSystemProperty("user.name") != null) defaults[n++] = "USER=" + getSystemProperty("user.name"); - if(!envHas("HOME",extra) && getSystemProperty("user.name") != null) + if(!envHas("HOME",extra) && getSystemProperty("user.home") != null) defaults[n++] = "HOME=" + getSystemProperty("user.home"); if(!envHas("SHELL",extra)) defaults[n++] = "SHELL=/bin/sh"; if(!envHas("TERM",extra)) defaults[n++] = "TERM=vt100"; @@ -82,18 +80,18 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private static class ProcessTableFullExn extends RuntimeException { } void _started() { - UnixRuntime[] tasks = gd.tasks; - synchronized(gd) { + UnixRuntime[] tasks = gs.tasks; + synchronized(gs) { if(pid != 0) { if(tasks[pid] == null || tasks[pid].pid != pid) throw new Error("should never happen"); } else { int newpid = -1; - int nextPID = gd.nextPID; - for(int i=nextPID;i= gd.tasks.length)) return -ECHILD; + if(pid !=-1 && (pid <= 0 || pid >= gs.tasks.length)) return -ECHILD; if(children == null) return blocking ? -ECHILD : 0; UnixRuntime done = null; @@ -169,7 +168,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(pid == -1) { if(exitedChildren.size() > 0) done = (UnixRuntime)exitedChildren.remove(exitedChildren.size() - 1); } else if(pid > 0) { - UnixRuntime t = gd.tasks[pid]; + UnixRuntime t = gs.tasks[pid]; if(t.parent != this) return -ECHILD; if(t.state == EXITED) { if(!exitedChildren.remove(t)) throw new Error("should never happen"); @@ -177,14 +176,14 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } } else { // process group stuff, EINVAL returned above - throw new Error("should never happen"); + throw new Error("should never happen"); } if(done == null) { if(!blocking) return 0; try { children.wait(); } catch(InterruptedException e) {} - System.err.println("waitpid woke up: " + exitedChildren.size()); + //System.err.println("waitpid woke up: " + exitedChildren.size()); } else { - gd.tasks[done.pid] = null; + gs.tasks[done.pid] = null; break; } } @@ -198,7 +197,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(children != null) synchronized(children) { for(Enumeration e = exitedChildren.elements(); e.hasMoreElements(); ) { UnixRuntime child = (UnixRuntime) e.nextElement(); - gd.tasks[child.pid] = null; + gs.tasks[child.pid] = null; } exitedChildren.clear(); for(Enumeration e = activeChildren.elements(); e.hasMoreElements(); ) { @@ -210,11 +209,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { UnixRuntime _parent = parent; if(_parent == null) { - gd.tasks[pid] = null; + gs.tasks[pid] = null; } else { synchronized(_parent.children) { if(parent == null) { - gd.tasks[pid] = null; + gs.tasks[pid] = null; } else { parent.activeChildren.remove(this); parent.exitedChildren.add(this); @@ -225,7 +224,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } protected Object clone() throws CloneNotSupportedException { - UnixRuntime r = (UnixRuntime) super.clone(); + UnixRuntime r = (UnixRuntime) super.clone(); r.pid = 0; r.parent = null; r.children = null; @@ -251,10 +250,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { try { r._started(); } catch(ProcessTableFullExn e) { - return -ENOMEM; + return -ENOMEM; } - System.err.println("fork " + pid + " -> " + r.pid + " tasks[" + r.pid + "] = " + gd.tasks[r.pid]); + //System.err.println("fork " + pid + " -> " + r.pid + " tasks[" + r.pid + "] = " + gd.tasks[r.pid]); if(children == null) { children = new Object(); activeChildren = new Vector(); @@ -282,10 +281,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public static int runAndExec(UnixRuntime r, String[] argv) { r.start(argv); return executeAndExec(r); } public static int executeAndExec(UnixRuntime r) { - for(;;) { + for(;;) { for(;;) { if(r.execute()) break; - System.err.println("WARNING: Pause requested while executing runAndExec()"); + if(STDERR_DIAG) System.err.println("WARNING: Pause requested while executing runAndExec()"); } if(r.state != EXECED) return r.exitStatus(); r = r.execedRuntime; @@ -293,7 +292,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } private String[] readStringArray(int addr) throws ReadFaultException { - int count = 0; + int count = 0; for(int p=addr;memRead(p) != 0;p+=4) count++; String[] a = new String[count]; for(int i=0,p=addr;i= OPEN_MAX) return -EBADFD; + if(fds[oldd] == null) return -EBADFD; + FD fd = fds[oldd].dup(); + int newd = addFD(fd); + if(newd < 0) { fd.close(); return -ENFILE; } + return newd; + } + private int sys_stat(int cstring, int addr) throws FaultException, ErrnoException { - FStat s = gd.stat(this,normalizePath(cstring(cstring))); + FStat s = gs.stat(this,normalizePath(cstring(cstring))); if(s == null) return -ENOENT; return stat(s,addr); } private int sys_lstat(int cstring, int addr) throws FaultException, ErrnoException { - FStat s = gd.lstat(this,normalizePath(cstring(cstring))); + FStat s = gs.lstat(this,normalizePath(cstring(cstring))); if(s == null) return -ENOENT; return stat(s,addr); } private int sys_mkdir(int cstring, int mode) throws FaultException, ErrnoException { - gd.mkdir(this,normalizePath(cstring(cstring)),mode); + gs.mkdir(this,normalizePath(cstring(cstring)),mode); return 0; } - private int sys_getcwd(int addr, int size) throws FaultException, ErrnoException { byte[] b = getBytes(cwd); if(size == 0) return -EINVAL; @@ -420,13 +481,23 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_chdir(int addr) throws ErrnoException, FaultException { String path = normalizePath(cstring(addr)); - System.err.println("Chdir: " + cstring(addr) + " -> " + path + " pwd: " + cwd); - if(gd.stat(this,path).type() != FStat.S_IFDIR) return -ENOTDIR; + //System.err.println("Chdir: " + cstring(addr) + " -> " + path + " pwd: " + cwd); + if(gs.stat(this,path).type() != FStat.S_IFDIR) return -ENOTDIR; cwd = path; - System.err.println("Now: [" + cwd + "]"); + //System.err.println("Now: [" + cwd + "]"); return 0; } + private int sys_getdents(int fdn, int addr, int count, int seekptr) throws FaultException, ErrnoException { + count = Math.min(count,MAX_CHUNK); + if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; + if(fds[fdn] == null) return -EBADFD; + byte[] buf = byteBuf(count); + int n = fds[fdn].getdents(buf,0,count); + copyout(buf,addr,n); + return n; + } + // FEATURE: Run through the fork/wait stuff one more time public static class GlobalState { protected static final int OPEN = 1; @@ -437,7 +508,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { final UnixRuntime[] tasks; int nextPID = 1; - private final MP[][] mps = new MP[128][]; + private MP[] mps = new MP[0]; private FS root; public GlobalState() { this(255); } @@ -445,7 +516,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public GlobalState(int maxProcs, boolean defaultMounts) { tasks = new UnixRuntime[maxProcs+1]; if(defaultMounts) { - root = new HostFS(); + addMount("/",new HostFS()); addMount("/dev",new DevFS()); } } @@ -464,61 +535,75 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(!path.startsWith("/")) throw new IllegalArgumentException("Mount point doesn't start with a /"); if(path.equals("/")) return root; path = path.substring(1); - int f = path.charAt(0) & 0x7f; - for(int i=0;mps[f] != null && i < mps[f].length;i++) - if(mps[f][i].path.equals(path)) return mps[f][i].fs; + for(int i=0;i 0) outp--; while(outp > 0 && out[outp] != '/') outp--; - System.err.println("After ..: " + new String(out,0,outp)); + //System.err.println("After ..: " + new String(out,0,outp)); continue; } inp++; @@ -706,7 +772,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return new String(out,0,outp); } - FStat hostFStat(final File f) { + FStat hostFStat(final File f, Object data) { boolean e = false; try { FileInputStream fis = new FileInputStream(f); @@ -716,19 +782,34 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } fis.close(); } catch(IOException e2) { } - return new HostFStat(f,e); + HostFS fs = (HostFS) data; + final int inode = fs.inodes.get(f.getAbsolutePath()); + final int devno = fs.devno; + return new HostFStat(f,e) { + public int inode() { return inode; } + public int dev() { return devno; } + }; } - // FIXME: inode stuff - FD hostFSDirFD(File f) { return FS.directoryFD(f.list(),f.hashCode()); } + FD hostFSDirFD(File f, Object _fs) { + HostFS fs = (HostFS) _fs; + return fs.new HostDirFD(f); + } public static class HostFS extends FS { + InodeCache inodes = new InodeCache(4000); protected File root; public File getRoot() { return root; } private static File hostRootDir() { + if(getSystemProperty("nestedvm.root") != null) { + File f = new File(getSystemProperty("nestedvm.root")); + if(f.isDirectory()) return f; + // fall through to case below + } String cwd = getSystemProperty("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()); return f; @@ -739,7 +820,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(sep != '/') { char buf[] = path.toCharArray(); for(int i=0;i>>24)&0xff); + buf[off+1] = (byte)((n>>>16)&0xff); + buf[off+2] = (byte)((n>>> 8)&0xff); + buf[off+3] = (byte)((n>>> 0)&0xff); + } + + public static abstract class DirFD extends FD { + private int pos = -2; + + protected abstract int size(); + protected abstract String name(int n); + protected abstract int inode(int n); + protected abstract int myDev(); + protected int parentInode() { return -1; } + protected int myInode() { return -1; } + + public int getdents(byte[] buf, int off, int len) { + int ooff = off; + int ino; + int reclen; + OUTER: for(;len > 0 && pos < size();pos++){ + switch(pos) { + case -2: + case -1: + ino = pos == -1 ? parentInode() : myInode(); + if(ino == -1) continue; + reclen = 9 + (pos == -1 ? 2 : 1); + if(reclen > len) break OUTER; + buf[off+8] = '.'; + if(pos == -1) buf[off+9] = '.'; + break; + default: { + String f = name(pos); + byte[] fb = getBytes(f); + reclen = fb.length + 9; + if(reclen > len) break OUTER; + ino = inode(pos); + System.arraycopy(fb,0,buf,off+8,fb.length); + } + } + buf[off+reclen-1] = 0; // null terminate + reclen = (reclen + 3) & ~3; // add padding + putInt(buf,off,reclen); + putInt(buf,off+4,ino); + off += reclen; + len -= reclen; + } + return off-ooff; + } + + protected FStat _fstat() { + return new FStat() { + public int type() { return S_IFDIR; } + public int inode() { return myInode(); } + public int dev() { return myDev(); } + }; + } } public static class DevFS extends FS { - private static class DevFStat extends FStat { - public int dev() { return 1; } + private static final int ROOT_INODE = 1; + private static final int NULL_INODE = 2; + private static final int ZERO_INODE = 3; + private static final int FD_INODE = 4; + private static final int FD_INODES = 32; + + private class DevFStat extends FStat { + public int dev() { return devno; } public int mode() { return 0666; } public int type() { return S_IFCHR; } public int nlink() { return 1; } } - private static FD devZeroFD = new FD() { + + private abstract class DevDirFD extends DirFD { + public int myDev() { return devno; } + } + + private FD devZeroFD = new FD() { public boolean readable() { return true; } public boolean writable() { return true; } public int read(byte[] a, int off, int length) { Arrays.fill(a,off,off+length,(byte)0); return length; } public int write(byte[] a, int off, int length) { return length; } public int seek(int n, int whence) { return 0; } - public FStat _fstat() { return new DevFStat(); } + public FStat _fstat() { return new DevFStat(){ public int inode() { return ZERO_INODE; } }; } }; - private static FD devNullFD = new FD() { + private FD devNullFD = new FD() { public boolean readable() { return true; } public boolean writable() { return true; } public int read(byte[] a, int off, int length) { return 0; } public int write(byte[] a, int off, int length) { return length; } public int seek(int n, int whence) { return 0; } - public FStat _fstat() { return new DevFStat(); } + public FStat _fstat() { return new DevFStat(){ public int inode() { return NULL_INODE; } }; } }; public FD open(UnixRuntime r, String path, int mode, int flags) throws ErrnoException { @@ -816,15 +983,42 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } if(path.equals("fd")) { int count=0; - for(int i=0;i