X-Git-Url: http://git.megacz.com/?p=nestedvm.git;a=blobdiff_plain;f=src%2Forg%2Fibex%2Fnestedvm%2FUnixRuntime.java;h=0b50ee30b65315cd3500d455d6b3bf71d33bf1e3;hp=b4f651d2facc369cb5d807e9310c81826eaf8f3e;hb=18f9d34628d03afdf74b95ccd96e6e2e8441fb54;hpb=8eb5962b879977e1a7975f9077c9ac86859deb48 diff --git a/src/org/ibex/nestedvm/UnixRuntime.java b/src/org/ibex/nestedvm/UnixRuntime.java index b4f651d..0b50ee3 100644 --- a/src/org/ibex/nestedvm/UnixRuntime.java +++ b/src/org/ibex/nestedvm/UnixRuntime.java @@ -1,6 +1,8 @@ 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.*; @@ -14,7 +16,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public final int getPid() { return pid; } private static final GlobalState defaultGS = new GlobalState(); - private GlobalState gs = defaultGS; + private GlobalState gs; public void setGlobalState(GlobalState gs) { if(state != STOPPED) throw new IllegalStateException("can't change GlobalState when running"); this.gs = gs; @@ -31,14 +33,36 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private Vector activeChildren; private Vector exitedChildren; - protected UnixRuntime(int pageSize, int totalPages) { - super(pageSize,totalPages); + protected UnixRuntime(int pageSize, int totalPages) { this(pageSize,totalPages,false); } + protected UnixRuntime(int pageSize, int totalPages, boolean exec) { + super(pageSize,totalPages,exec); - // FEATURE: Do the proper mangling for non-unix hosts - String userdir = getSystemProperty("user.dir"); - cwd = - userdir != null && userdir.startsWith("/") && File.separatorChar == '/' && getSystemProperty("nestedvm.root") == null - ? userdir.substring(1) : ""; + 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?"":"/"); + } + } + } } private static String posixTZ() { @@ -66,12 +90,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { String[] defaults = new String[6]; int n=0; 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.home") != null) - defaults[n++] = "HOME=" + getSystemProperty("user.home"); + 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("SHELL",extra)) defaults[n++] = "SHELL=/bin/sh"; - if(!envHas("TERM",extra)) defaults[n++] = "TERM=vt100"; + if(!envHas("TERM",extra) && !win32Hacks) defaults[n++] = "TERM=vt100"; if(!envHas("TZ",extra)) defaults[n++] = "TZ=" + posixTZ(); if(!envHas("PATH",extra)) defaults[n++] = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"; String[] env = new String[extra.length+n]; @@ -134,6 +158,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case SYS_accept: return sys_accept(a,b,c); case SYS_shutdown: return sys_shutdown(a,b); case SYS_sysctl: return sys_sysctl(a,b,c,d,e,f); + case SYS_sendto: return sys_sendto(a,b,c,d,e,f); + case SYS_recvfrom: return sys_recvfrom(a,b,c,d,e,f); + case SYS_select: return sys_select(a,b,c,d,e); default: return super._syscall(syscall,a,b,c,d,e,f); } @@ -147,6 +174,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return parent == null ? 1 : parent.pid; } + // FEATURE: Signal handling + // check flag only on backwards jumps to basic blocks without compulsatory checks + // (see A Portable Research Framework for the Execution of Java Bytecode - Etienne Gagnon, Chapter 2) + /** The kill syscall. SIGSTOP, SIGTSTO, SIGTTIN, and SIGTTOUT pause the process. SIGCONT, SIGCHLD, SIGIO, and SIGWINCH are ignored. @@ -162,16 +193,13 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { case 18: // SIGTSTP case 21: // SIGTTIN case 22: // SIGTTOU - state = PAUSED; - break; case 19: // SIGCONT case 20: // SIGCHLD case 23: // SIGIO case 28: // SIGWINCH break; default: - // FEATURE: This is ugly, make a clean interface to sys_exit - return syscall(SYS_exit,128+signal,0,0,0,0,0); + exit(128+signal, true); } return 0; } @@ -198,6 +226,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { exitedChildren.removeElementAt(exitedChildren.size() - 1); } } else if(pid > 0) { + if(pid >= gs.tasks.length) return -ECHILD; UnixRuntime t = gs.tasks[pid]; if(t.parent != this) return -ECHILD; if(t.state == EXITED) { @@ -263,9 +292,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } private int sys_fork() { - CPUState state = new CPUState(); - getCPUState(state); - int sp = state.r[SP]; final UnixRuntime r; try { @@ -291,6 +317,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } activeChildren.addElement(r); + CPUState state = new CPUState(); + getCPUState(state); state.r[V0] = 0; // return 0 to child state.pc += 4; // skip over syscall instruction r.setCPUState(state); @@ -348,7 +376,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(o instanceof Class) { Class c = (Class) o; try { - return exec((UnixRuntime) c.newInstance(),argv,envp); + 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; @@ -389,10 +418,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } - // FEATURE: Make sure fstat info is correct - // FEATURE: This could be faster if we did direct copies from each process' memory - // FEATURE: Check this logic one more time - public static class Pipe { + static class Pipe { private final byte[] pipebuf = new byte[PIPE_BUF*4]; private int readPos; private int writePos; @@ -401,7 +427,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public final FD writer = new Writer(); public class Reader extends FD { - protected FStat _fstat() { return new FStat(); } + protected FStat _fstat() { return new SocketFStat(); } public int read(byte[] buf, int off, int len) throws ErrnoException { if(len == 0) return 0; synchronized(Pipe.this) { @@ -416,11 +442,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return len; } } + public int flags() { return O_RDONLY; } public void _close() { synchronized(Pipe.this) { readPos = -1; Pipe.this.notify(); } } } public class Writer extends FD { - protected FStat _fstat() { return new FStat(); } + protected FStat _fstat() { return new SocketFStat(); } public int write(byte[] buf, int off, int len) throws ErrnoException { if(len == 0) return 0; synchronized(Pipe.this) { @@ -440,6 +467,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return len; } } + public int flags() { return O_WRONLY; } public void _close() { synchronized(Pipe.this) { writePos = -1; Pipe.this.notify(); } } } } @@ -533,8 +561,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return n; } - // FIXME: UDP is totally broken - static class SocketFD extends FD { public static final int TYPE_STREAM = 0; public static final int TYPE_DGRAM = 1; @@ -544,19 +570,31 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { int flags; int options; - Object o; + + Socket s; + ServerSocket ss; + DatagramSocket ds; + InetAddress bindAddr; int bindPort = -1; + InetAddress connectAddr; + int connectPort = -1; + DatagramPacket dp; InputStream is; OutputStream os; - public SocketFD(int type) { flags = type; } + private static final byte[] EMPTY = new byte[0]; + public SocketFD(int type) { + flags = type; + if(type == TYPE_DGRAM) + dp = new DatagramPacket(EMPTY,0); + } public void setOptions() { try { - if(o != null && type() == TYPE_STREAM && !listen()) { - Platform.socketSetKeepAlive((Socket)o,(options & SO_KEEPALIVE) != 0); + if(s != null && type() == TYPE_STREAM && !listen()) { + Platform.socketSetKeepAlive(s,(options & SO_KEEPALIVE) != 0); } } catch(SocketException e) { if(STDERR_DIAG) e.printStackTrace(); @@ -564,76 +602,87 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } public void _close() { - if(o != null) { - try { - if(type() == TYPE_STREAM) { - if(listen()) ((ServerSocket)o).close(); - else ((Socket)o).close(); - } else { - ((DatagramSocket)o).close(); - } - } catch(IOException e) { - /* ignore */ - } + try { + if(s != null) s.close(); + if(ss != null) ss.close(); + if(ds != null) ds.close(); + } catch(IOException e) { + /* ignore */ } } public int read(byte[] a, int off, int length) throws ErrnoException { - if(type() == TYPE_STREAM) { - if(is == null) throw new ErrnoException(EPIPE); - try { - int n = is.read(a,off,length); - return n < 0 ? 0 : n; - } catch(IOException e) { - throw new ErrnoException(EIO); - } - } else { - if(off != 0) throw new IllegalArgumentException("off must be 0"); - DatagramSocket ds = (DatagramSocket) o; - dp.setData(a); - dp.setLength(length); - try { - ds.receive(dp); - } catch(IOException e) { - throw new ErrnoException(EIO); - } - return dp.getLength(); + if(type() == TYPE_DGRAM) return recvfrom(a,off,length,null,null); + if(is == null) throw new ErrnoException(EPIPE); + try { + int n = is.read(a,off,length); + return n < 0 ? 0 : n; + } catch(IOException e) { + throw new ErrnoException(EIO); } } - public int write(byte[] a, int off, int length) throws ErrnoException { - if(type() == TYPE_STREAM) { - if(os == null) throw new ErrnoException(EPIPE); - try { - os.write(a,off,length); - return length; - } catch(IOException e) { - throw new ErrnoException(EIO); - } - } else { - if(off != 0) throw new IllegalArgumentException("off must be 0"); - DatagramSocket ds = (DatagramSocket) o; - dp.setData(a); - dp.setLength(length); - try { - ds.send(dp); - } catch(IOException e) { - throw new ErrnoException(EIO); - } - return dp.getLength(); - } + public int recvfrom(byte[] a, int off, int length, InetAddress[] sockAddr, int[] port) throws ErrnoException { + if(type() == TYPE_STREAM) return read(a,off,length); + + if(off != 0) throw new IllegalArgumentException("off must be 0"); + dp.setData(a); + dp.setLength(length); + try { + if(ds == null) ds = new DatagramSocket(); + ds.receive(dp); + } catch(IOException e) { + if(STDERR_DIAG) e.printStackTrace(); + throw new ErrnoException(EIO); + } + if(sockAddr != null) { + sockAddr[0] = dp.getAddress(); + port[0] = dp.getPort(); + } + return dp.getLength(); } + + public int write(byte[] a, int off, int length) throws ErrnoException { + if(type() == TYPE_DGRAM) return sendto(a,off,length,null,-1); - // FEATURE: Check that these are correct - public int flags() { - if(is != null && os != null) return O_RDWR; - if(is != null) return O_RDONLY; - if(os != null) return O_WRONLY; - return 0; + if(os == null) throw new ErrnoException(EPIPE); + try { + os.write(a,off,length); + return length; + } catch(IOException e) { + throw new ErrnoException(EIO); + } } - // FEATURE: Populate this properly - public FStat _fstat() { return new FStat(); } + public int sendto(byte[] a, int off, int length, InetAddress destAddr, int destPort) throws ErrnoException { + if(off != 0) throw new IllegalArgumentException("off must be 0"); + if(type() == TYPE_STREAM) return write(a,off,length); + + if(destAddr == null) { + destAddr = connectAddr; + destPort = connectPort; + + if(destAddr == null) throw new ErrnoException(ENOTCONN); + } + + dp.setAddress(destAddr); + dp.setPort(destPort); + dp.setData(a); + dp.setLength(length); + + try { + if(ds == null) ds = new DatagramSocket(); + ds.send(dp); + } catch(IOException e) { + if(STDERR_DIAG) e.printStackTrace(); + if("Network is unreachable".equals(e.getMessage())) throw new ErrnoException(EHOSTUNREACH); + throw new ErrnoException(EIO); + } + return dp.getLength(); + } + + public int flags() { return O_RDWR; } + public FStat _fstat() { return new SocketFStat(); } } private int sys_socket(int domain, int type, int proto) { @@ -652,7 +701,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_connect(int fdn, int addr, int namelen) throws ErrnoException, FaultException { SocketFD fd = getSocketFD(fdn); - if(fd.type() == SocketFD.TYPE_STREAM && fd.o != null) return -EISCONN; + if(fd.type() == SocketFD.TYPE_STREAM && (fd.s != null || fd.ss != null)) return -EISCONN; int word1 = memRead(addr); if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -666,22 +715,21 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return -EADDRNOTAVAIL; } + fd.connectAddr = inetAddr; + fd.connectPort = port; + try { switch(fd.type()) { case SocketFD.TYPE_STREAM: { Socket s = new Socket(inetAddr,port); - fd.o = s; + fd.s = s; fd.setOptions(); fd.is = s.getInputStream(); fd.os = s.getOutputStream(); break; } - case SocketFD.TYPE_DGRAM: { - if(fd.dp == null) fd.dp = new DatagramPacket(null,0); - fd.dp.setAddress(inetAddr); - fd.dp.setPort(port); + case SocketFD.TYPE_DGRAM: break; - } default: throw new Error("should never happen"); } @@ -761,7 +809,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_bind(int fdn, int addr, int namelen) throws FaultException, ErrnoException { SocketFD fd = getSocketFD(fdn); - if(fd.type() == SocketFD.TYPE_STREAM && fd.o != null) return -EISCONN; + if(fd.type() == SocketFD.TYPE_STREAM && (fd.s != null || fd.ss != null)) return -EISCONN; int word1 = memRead(addr); if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; int port = word1 & 0xffff; @@ -784,10 +832,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } case SocketFD.TYPE_DGRAM: { - DatagramSocket s = (DatagramSocket) fd.o; - if(s != null) s.close(); + if(fd.ds != null) fd.ds.close(); try { - fd.o = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); + fd.ds = inetAddr != null ? new DatagramSocket(port,inetAddr) : new DatagramSocket(port); } catch(IOException e) { return -EADDRINUSE; } @@ -801,11 +848,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_listen(int fdn, int backlog) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM) return -EOPNOTSUPP; - if(fd.o != null) return -EISCONN; + if(fd.ss != null || fd.s != null) return -EISCONN; if(fd.bindPort < 0) return -EOPNOTSUPP; try { - fd.o = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); + fd.ss = new ServerSocket(fd.bindPort,backlog,fd.bindAddr); fd.flags |= SocketFD.LISTEN; return 0; } catch(IOException e) { @@ -821,7 +868,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { int size = memRead(lenaddr); - ServerSocket s = (ServerSocket) fd.o; + ServerSocket s = fd.ss; Socket client; try { client = s.accept(); @@ -837,7 +884,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } SocketFD clientFD = new SocketFD(SocketFD.TYPE_STREAM); - clientFD.o = client; + clientFD.s = client; try { clientFD.is = client.getInputStream(); clientFD.os = client.getOutputStream(); @@ -852,9 +899,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private int sys_shutdown(int fdn, int how) throws ErrnoException { SocketFD fd = getSocketFD(fdn); if(fd.type() != SocketFD.TYPE_STREAM || fd.listen()) return -EOPNOTSUPP; - if(fd.o == null) return -ENOTCONN; + if(fd.s == null) return -ENOTCONN; - Socket s = (Socket) fd.o; + Socket s = fd.s; try { if(how == SHUT_RD || how == SHUT_RDWR) Platform.socketHalfClose(s,false); @@ -866,6 +913,58 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { return 0; } + private int sys_sendto(int fdn, int addr, int count, int flags, int destAddr, int socklen) throws ErrnoException,ReadFaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + int word1 = memRead(destAddr); + if( ((word1 >>> 16)&0xff) != AF_INET) return -EAFNOSUPPORT; + int port = word1 & 0xffff; + InetAddress inetAddr; + byte[] ip = new byte[4]; + copyin(destAddr+4,ip,4); + try { + inetAddr = Platform.inetAddressFromBytes(ip); + } catch(UnknownHostException e) { + return -EADDRNOTAVAIL; + } + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + copyin(addr,buf,count); + try { + return fd.sendto(buf,0,count,inetAddr,port); + } catch(ErrnoException e) { + if(e.errno == EPIPE) exit(128+13,true); + throw e; + } + } + + private int sys_recvfrom(int fdn, int addr, int count, int flags, int sourceAddr, int socklenAddr) throws ErrnoException, FaultException { + SocketFD fd = getSocketFD(fdn); + if(flags != 0) throw new ErrnoException(EINVAL); + + InetAddress[] inetAddr = sourceAddr == 0 ? null : new InetAddress[1]; + int[] port = sourceAddr == 0 ? null : new int[1]; + + count = Math.min(count,MAX_CHUNK); + byte[] buf = byteBuf(count); + int n = fd.recvfrom(buf,0,count,inetAddr,port); + copyout(buf,addr,n); + + if(sourceAddr != 0) { + memWrite(sourceAddr,(AF_INET << 16) | port[0]); + byte[] ip = inetAddr[0].getAddress(); + copyout(ip,sourceAddr+4,4); + } + + return n; + } + + private int sys_select(int n, int readFDs, int writeFDs, int exceptFDs, int timevalAddr) throws ReadFaultException, ErrnoException { + return -ENOSYS; + } + private static String hostName() { try { return InetAddress.getLocalHost().getHostName(); @@ -913,63 +1012,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } return 0; } - - - /*public int sys_opensocket(int cstring, int port) throws FaultException, ErrnoException { - String hostname = cstring(cstring); - try { - FD fd = new SocketFD(new Socket(hostname,port)); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - } - - private static class ListenSocketFD extends FD { - ServerSocket s; - public ListenSocketFD(ServerSocket s) { this.s = s; } - public int flags() { return 0; } - // FEATURE: What should these be? - public FStat _fstat() { return new FStat(); } - public void _close() { try { s.close(); } catch(IOException e) { } } - } - - public int sys_listensocket(int port) { - try { - ListenSocketFD fd = new ListenSocketFD(new ServerSocket(port)); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - } - - public int sys_accept(int fdn) { - if(fdn < 0 || fdn >= OPEN_MAX) return -EBADFD; - if(fds[fdn] == null) return -EBADFD; - if(!(fds[fdn] instanceof ListenSocketFD)) return -EBADFD; - try { - ServerSocket s = ((ListenSocketFD)fds[fdn]).s; - SocketFD fd = new SocketFD(s.accept()); - int n = addFD(fd); - if(n == -1) fd.close(); - return n; - } catch(IOException e) { - return -EIO; - } - }*/ - // FEATURE: Run through the fork/wait stuff one more time - public static class GlobalState { - protected static final int OPEN = 1; - protected static final int STAT = 2; - protected static final int LSTAT = 3; - protected static final int MKDIR = 4; - protected static final int UNLINK = 5; - + public static class GlobalState { final UnixRuntime[] tasks; int nextPID = 1; @@ -1051,7 +1095,6 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { mps = newMPS; } - // FEATURE: We shouldn't need to special case the root dir, it should work in the MP array private Object fsop(int op, UnixRuntime r, String normalizedPath, int arg1, int arg2) throws ErrnoException { int pl = normalizedPath.length(); if(pl != 0) { @@ -1061,29 +1104,17 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { MP mp = list[i]; int mpl = mp.path.length(); if(normalizedPath.startsWith(mp.path) && (pl == mpl || normalizedPath.charAt(mpl) == '/')) - return dispatch(mp.fs,op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); + return mp.fs.dispatch(op,r,pl == mpl ? "" : normalizedPath.substring(mpl+1),arg1,arg2); } } - return dispatch(root,op,r,normalizedPath,arg1,arg2); + return root.dispatch(op,r,normalizedPath,arg1,arg2); } - // FEATURE: move this into FS so some filesystem can override it directly (devfs) - private static Object dispatch(FS fs, int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException { - switch(op) { - case OPEN: return fs.open(r,path,arg1,arg2); - case STAT: return fs.stat(r,path); - case LSTAT: return fs.lstat(r,path); - case MKDIR: fs.mkdir(r,path,arg1); return null; - case UNLINK: fs.unlink(r,path); return null; - default: throw new Error("should never happen"); - } - } - - public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(OPEN,r,path,flags,mode); } - public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(STAT,r,path,0,0); } - public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(LSTAT,r,path,0,0); } - public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(MKDIR,r,path,mode,0); } - public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(UNLINK,r,path,0,0); } + public final FD open(UnixRuntime r, String path, int flags, int mode) throws ErrnoException { return (FD) fsop(FS.OPEN,r,path,flags,mode); } + public final FStat stat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.STAT,r,path,0,0); } + public final FStat lstat(UnixRuntime r, String path) throws ErrnoException { return (FStat) fsop(FS.LSTAT,r,path,0,0); } + public final void mkdir(UnixRuntime r, String path, int mode) throws ErrnoException { fsop(FS.MKDIR,r,path,mode,0); } + public final void unlink(UnixRuntime r, String path) throws ErrnoException { fsop(FS.UNLINK,r,path,0,0); } private Hashtable execCache = new Hashtable(); private static class CacheEnt { @@ -1094,9 +1125,9 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } public synchronized Object exec(UnixRuntime r, String path) throws ErrnoException { - // FIXME: Hideous hack to make a standalone busybox possible - if(path.equals("bin/busybox") && Boolean.valueOf(getSystemProperty("nestedvm.busyboxhack")).booleanValue()) - return r.getClass(); + // HACK: Hideous hack to make a standalone busybox possible + if(path.equals("bin/busybox") && r.getClass().getName().endsWith("BusyBox")) return r.getClass(); + FStat fstat = stat(r,path); if(fstat == null) return null; long mtime = fstat.mtime(); @@ -1166,7 +1197,7 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { // its an elf binary try { s.seek(0); - Class c = RuntimeCompiler.compile(s); + Class c = RuntimeCompiler.compile(s,"unixruntime"); //System.err.println("Compile succeeded: " + c); ent = new CacheEnt(mtime,size,c); } catch(Compiler.Exn e) { @@ -1188,9 +1219,26 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { } public abstract static class FS { + static final int OPEN = 1; + static final int STAT = 2; + static final int LSTAT = 3; + static final int MKDIR = 4; + static final int UNLINK = 5; + GlobalState owner; int devno; + Object dispatch(int op, UnixRuntime r, String path, int arg1, int arg2) throws ErrnoException { + switch(op) { + case OPEN: return open(r,path,arg1,arg2); + case STAT: return stat(r,path); + case LSTAT: return lstat(r,path); + case MKDIR: mkdir(r,path,arg1); return null; + case UNLINK: unlink(r,path); return null; + default: throw new Error("should never happen"); + } + } + public FStat lstat(UnixRuntime r, String path) throws ErrnoException { return stat(r,path); } // If this returns null it'll be truned into an ENOENT @@ -1201,10 +1249,11 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public abstract void unlink(UnixRuntime r, String path) throws ErrnoException; } - // FEATURE: chroot support in here + // chroot support should go in here if it is ever implemented chroot support in here private String normalizePath(String path) { boolean absolute = path.startsWith("/"); int cwdl = cwd.length(); + // NOTE: This isn't just a fast path, it handles cases the code below doesn't if(!path.startsWith(".") && path.indexOf("./") == -1 && path.indexOf("//") == -1 && !path.endsWith(".")) return absolute ? path.substring(1) : cwdl == 0 ? path : path.length() == 0 ? cwd : cwd + "/" + path; @@ -1219,23 +1268,29 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { cwd.getChars(0,cwdl,out,0); outp = cwdl; } - + path.getChars(0,path.length(),in,0); while(in[inp] != 0) { - if(inp != 0 || cwdl==0) { - if(in[inp] != '/') { out[outp++] = in[inp++]; continue; } + if(inp != 0) { + while(in[inp] != 0 && in[inp] != '/') { out[outp++] = in[inp++]; } + if(in[inp] == '\0') break; while(in[inp] == '/') inp++; } - if(in[inp] == '\0') continue; + + // Just read a / + if(in[inp] == '\0') break; if(in[inp] != '.') { out[outp++] = '/'; out[outp++] = in[inp++]; continue; } + // Just read a /. if(in[inp+1] == '\0' || in[inp+1] == '/') { inp++; continue; } if(in[inp+1] == '.' && (in[inp+2] == '\0' || in[inp+2] == '/')) { // .. + // Just read a /..{$,/} inp += 2; if(outp > 0) outp--; while(outp > 0 && out[outp] != '/') outp--; //System.err.println("After ..: " + new String(out,0,outp)); continue; } + // Just read a /.[^.] or /..[^/$] inp++; out[outp++] = '/'; out[outp++] = '.'; @@ -1274,17 +1329,19 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { protected File root; public File getRoot() { return root; } - private static File hostRootDir() { - if(getSystemProperty("nestedvm.root") != null) { - File f = new File(getSystemProperty("nestedvm.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 = getSystemProperty("user.dir"); + 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; } @@ -1355,7 +1412,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { public int inode(int n) { return inodes.get(children[n].getAbsolutePath()); } public int parentInode() { File parent = getParentFile(f); - return parent == null ? -1 : inodes.get(parent.getAbsolutePath()); + // HACK: myInode() isn't really correct if we're not the root + return parent == null ? myInode() : inodes.get(parent.getAbsolutePath()); } public int myInode() { return inodes.get(f.getAbsolutePath()); } public int myDev() { return devno; } @@ -1376,9 +1434,10 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { 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; } - + protected abstract int parentInode(); + protected abstract int myInode(); + public int flags() { return O_RDONLY; } + public int getdents(byte[] buf, int off, int len) { int ooff = off; int ino; @@ -1429,11 +1488,12 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { private static final int FD_INODE = 4; private static final int FD_INODES = 32; - private class DevFStat extends FStat { + private abstract 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; } + public abstract int inode(); } private abstract class DevDirFD extends DirFD { @@ -1449,12 +1509,14 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { 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 int inode() { return ZERO_INODE; } }; } + public int flags() { return O_RDWR; } }; private FD devNullFD = new FD() { 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 int inode() { return NULL_INODE; } }; } + public int flags() { return O_RDWR; } }; public FD open(UnixRuntime r, String path, int mode, int flags) throws ErrnoException { @@ -1488,8 +1550,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(path.equals("")) { return new DevDirFD() { public int myInode() { return ROOT_INODE; } - // FEATURE: Get the real parent inode somehow - public int parentInode() { return -1; } + // HACK: We don't have any clean way to get the parent inode + public int parentInode() { return ROOT_INODE; } public int inode(int n) { switch(n) { case 0: return NULL_INODE; @@ -1527,9 +1589,8 @@ public abstract class UnixRuntime extends Runtime implements Cloneable { if(r.fds[n] == null) return null; return r.fds[n].fstat(); } - // FEATURE: inode stuff - if(path.equals("fd")) return new FStat() { public int type() { return S_IFDIR; } public int mode() { return 0444; }}; - if(path.equals("")) return new FStat() { public int type() { return S_IFDIR; } public int mode() { return 0444; }}; + if(path.equals("fd")) return new FStat() { public int inode() { return FD_INODE; } public int dev() { return devno; } public int type() { return S_IFDIR; } public int mode() { return 0444; }}; + if(path.equals("")) return new FStat() { public int inode() { return ROOT_INODE; } public int dev() { return devno; } public int type() { return S_IFDIR; } public int mode() { return 0444; }}; return null; }