summaryrefslogtreecommitdiff
path: root/sysfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysfile.c')
-rw-r--r--sysfile.c477
1 files changed, 477 insertions, 0 deletions
diff --git a/sysfile.c b/sysfile.c
new file mode 100644
index 0000000..f533e01
--- /dev/null
+++ b/sysfile.c
@@ -0,0 +1,477 @@
+#include "types.h"
+#include "stat.h"
+#include "param.h"
+#include "mmu.h"
+#include "proc.h"
+#include "defs.h"
+#include "x86.h"
+#include "traps.h"
+#include "syscall.h"
+#include "spinlock.h"
+#include "buf.h"
+#include "fs.h"
+#include "fsvar.h"
+#include "elf.h"
+#include "fd.h"
+#include "fcntl.h"
+
+int
+sys_pipe(void)
+{
+ struct fd *rfd = 0, *wfd = 0;
+ int f1 = -1, f2 = -1;
+ struct proc *p = curproc[cpu()];
+ uint fdp;
+
+ if(pipe_alloc(&rfd, &wfd) < 0)
+ goto oops;
+ if((f1 = fd_ualloc()) < 0)
+ goto oops;
+ p->fds[f1] = rfd;
+ if((f2 = fd_ualloc()) < 0)
+ goto oops;
+ p->fds[f2] = wfd;
+ if(fetcharg(0, &fdp) < 0)
+ goto oops;
+ if(putint(p, fdp, f1) < 0)
+ goto oops;
+ if(putint(p, fdp+4, f2) < 0)
+ goto oops;
+ return 0;
+
+ oops:
+ if(rfd)
+ fd_close(rfd);
+ if(wfd)
+ fd_close(wfd);
+ if(f1 >= 0)
+ p->fds[f1] = 0;
+ if(f2 >= 0)
+ p->fds[f2] = 0;
+ return -1;
+}
+
+int
+sys_write(void)
+{
+ int fd, n, ret;
+ uint addr;
+ struct proc *p = curproc[cpu()];
+
+ if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(p->fds[fd] == 0)
+ return -1;
+ if(addr + n > p->sz)
+ return -1;
+
+ ret = fd_write(p->fds[fd], p->mem + addr, n);
+ return ret;
+}
+
+int
+sys_read(void)
+{
+ int fd, n, ret;
+ uint addr;
+ struct proc *p = curproc[cpu()];
+
+ if(fetcharg(0, &fd) < 0 || fetcharg(1, &addr) < 0 || fetcharg(2, &n) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(p->fds[fd] == 0)
+ return -1;
+ if(addr + n > p->sz)
+ return -1;
+ ret = fd_read(p->fds[fd], p->mem + addr, n);
+ return ret;
+}
+
+int
+sys_close(void)
+{
+ int fd;
+ struct proc *p = curproc[cpu()];
+
+ if(fetcharg(0, &fd) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(p->fds[fd] == 0)
+ return -1;
+ fd_close(p->fds[fd]);
+ p->fds[fd] = 0;
+ return 0;
+}
+
+int
+sys_open(void)
+{
+ struct proc *cp = curproc[cpu()];
+ struct inode *ip, *dp;
+ uint arg0, arg1;
+ int ufd;
+ struct fd *fd;
+ int l;
+ char *last;
+
+ if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0)
+ return -1;
+ if((l = checkstring(arg0)) < 0)
+ return -1;
+
+ if(arg1 & O_CREATE){
+ dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, &ip);
+ if(dp){
+ ip = mknod1(dp, last, T_FILE, 0, 0);
+ iput(dp);
+ if(ip == 0)
+ return -1;
+ } else if(ip == 0){
+ return -1;
+ } else if(ip->type == T_DIR){
+ iput(ip);
+ return -1;
+ }
+ } else {
+ ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
+ if(ip == 0)
+ return -1;
+ }
+ if(ip->type == T_DIR && ((arg1 & O_RDWR) || (arg1 & O_WRONLY))){
+ iput(ip);
+ return -1;
+ }
+
+ if((fd = fd_alloc()) == 0){
+ iput(ip);
+ return -1;
+ }
+ if((ufd = fd_ualloc()) < 0){
+ iput(ip);
+ fd_close(fd);
+ return -1;
+ }
+
+ iunlock(ip);
+ fd->type = FD_FILE;
+ if(arg1 & O_RDWR) {
+ fd->readable = 1;
+ fd->writable = 1;
+ } else if(arg1 & O_WRONLY) {
+ fd->readable = 0;
+ fd->writable = 1;
+ } else {
+ fd->readable = 1;
+ fd->writable = 0;
+ }
+ fd->ip = ip;
+ fd->off = 0;
+ cp->fds[ufd] = fd;
+
+ return ufd;
+}
+
+int
+sys_mknod(void)
+{
+ struct proc *cp = curproc[cpu()];
+ struct inode *nip;
+ uint arg0, arg1, arg2, arg3;
+ int l;
+
+ if(fetcharg(0, &arg0) < 0 || fetcharg(1, &arg1) < 0 ||
+ fetcharg(2, &arg2) < 0 || fetcharg(3, &arg3) < 0)
+ return -1;
+
+ if((l = checkstring(arg0)) < 0)
+ return -1;
+
+ if(l >= DIRSIZ)
+ return -1;
+
+ nip = mknod(cp->mem + arg0, (short) arg1, (short) arg2, (short) arg3);
+ if(nip)
+ iput(nip);
+ return (nip == 0) ? -1 : 0;
+}
+
+int
+sys_mkdir(void)
+{
+ struct proc *cp = curproc[cpu()];
+ struct inode *nip;
+ struct inode *dp;
+ uint arg0;
+ int l;
+ struct dirent de;
+ char *last;
+
+ if(fetcharg(0, &arg0) < 0)
+ return -1;
+
+ if((l = checkstring(arg0)) < 0)
+ return -1;
+
+ dp = namei(cp->mem + arg0, NAMEI_CREATE, 0, &last, 0);
+ if(dp == 0)
+ return -1;
+
+ nip = mknod1(dp, last, T_DIR, 0, 0);
+ if(nip == 0){
+ iput(dp);
+ return -1;
+ }
+
+ dp->nlink += 1;
+ iupdate(dp);
+
+ memset(de.name, '\0', DIRSIZ);
+ de.name[0] = '.';
+ de.inum = nip->inum;
+ writei(nip, (char*) &de, 0, sizeof(de));
+
+ de.inum = dp->inum;
+ de.name[1] = '.';
+ writei(nip, (char*) &de, sizeof(de), sizeof(de));
+
+ iput(dp);
+ iput(nip);
+
+ return 0;
+}
+
+
+int
+sys_chdir(void)
+{
+ struct proc *cp = curproc[cpu()];
+ struct inode *ip;
+ uint arg0;
+ int l;
+
+ if(fetcharg(0, &arg0) < 0)
+ return -1;
+
+ if((l = checkstring(arg0)) < 0)
+ return -1;
+
+ if((ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0)) == 0)
+ return -1;
+
+ if(ip == cp->cwd) {
+ iput(ip);
+ return 0;
+ }
+
+ if(ip->type != T_DIR) {
+ iput(ip);
+ return -1;
+ }
+
+ idecref(cp->cwd);
+ cp->cwd = ip;
+ iunlock(cp->cwd);
+ return 0;
+}
+
+int
+sys_unlink(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint arg0;
+ int r;
+
+ if(fetcharg(0, &arg0) < 0)
+ return -1;
+ if(checkstring(arg0) < 0)
+ return -1;
+ r = unlink(cp->mem + arg0);
+ return r;
+}
+
+int
+sys_fstat(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint fd, addr;
+ int r;
+
+ if(fetcharg(0, &fd) < 0)
+ return -1;
+ if(fetcharg(1, &addr) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(cp->fds[fd] == 0)
+ return -1;
+ if(addr + sizeof(struct stat) > cp->sz)
+ return -1;
+ r = fd_stat(cp->fds[fd], (struct stat*)(cp->mem + addr));
+ return r;
+}
+
+int
+sys_dup(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint fd, ufd1;
+
+ if(fetcharg(0, &fd) < 0)
+ return -1;
+ if(fd < 0 || fd >= NOFILE)
+ return -1;
+ if(cp->fds[fd] == 0)
+ return -1;
+ if((ufd1 = fd_ualloc()) < 0)
+ return -1;
+ cp->fds[ufd1] = cp->fds[fd];
+ fd_incref(cp->fds[ufd1]);
+ return ufd1;
+}
+
+int
+sys_link(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint name1, name2;
+ int r;
+
+ if(fetcharg(0, &name1) < 0 || checkstring(name1) < 0)
+ return -1;
+ if(fetcharg(1, &name2) < 0 || checkstring(name2) < 0)
+ return -1;
+ r = link(cp->mem + name1, cp->mem + name2);
+ return r;
+}
+
+int
+sys_exec(void)
+{
+ struct proc *cp = curproc[cpu()];
+ uint arg0, arg1, sz=0, ap, sp, p1, p2;
+ int i, nargs, argbytes, len;
+ struct inode *ip;
+ struct elfhdr elf;
+ struct proghdr ph;
+ char *mem = 0;
+
+ if(fetcharg(0, &arg0) < 0)
+ return -1;
+ if(fetcharg(1, &arg1) < 0)
+ return -1;
+ if(checkstring(arg0) < 0)
+ return -1;
+ ip = namei(cp->mem + arg0, NAMEI_LOOKUP, 0, 0, 0);
+ if(ip == 0)
+ return -1;
+
+ if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf))
+ goto bad;
+
+ if(elf.magic != ELF_MAGIC)
+ goto bad;
+
+ sz = 0;
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
+ sizeof(ph)) != sizeof(ph))
+ goto bad;
+ if(ph.type != ELF_PROG_LOAD)
+ continue;
+ if(ph.memsz < ph.filesz)
+ goto bad;
+ sz += ph.memsz;
+ }
+
+ sz += 4096 - (sz % 4096);
+ sz += 4096;
+
+ mem = kalloc(sz);
+ if(mem == 0)
+ goto bad;
+ memset(mem, 0, sz);
+
+ // arg1 is a pointer to an array of pointers to string.
+ nargs = 0;
+ argbytes = 0;
+ for(i = 0; ; i++){
+ if(fetchint(cp, arg1 + 4*i, &ap) < 0)
+ goto bad;
+ if(ap == 0)
+ break;
+ len = checkstring(ap);
+ if(len < 0)
+ goto bad;
+ nargs++;
+ argbytes += len + 1;
+ }
+
+ // argn\0
+ // ...
+ // arg0\0
+ // 0
+ // ptr to argn
+ // ...
+ // 12: ptr to arg0
+ // 8: argv (points to ptr to arg0)
+ // 4: argc
+ // 0: fake return pc
+ sp = sz - argbytes - (nargs+1)*4 - 4 - 4 - 4;
+ *(uint*)(mem + sp) = 0xffffffff;
+ *(uint*)(mem + sp + 4) = nargs;
+ *(uint*)(mem + sp + 8) = (uint)(sp + 12);
+
+ p1 = sp + 12;
+ p2 = sp + 12 + (nargs + 1) * 4;
+ for(i = 0; i < nargs; i++){
+ fetchint(cp, arg1 + 4*i, &ap);
+ len = checkstring(ap);
+ memmove(mem + p2, cp->mem + ap, len + 1);
+ *(uint*)(mem + p1) = p2;
+ p1 += 4;
+ p2 += len + 1;
+ }
+ *(uint*)(mem + p1) = 0;
+
+ // commit to the new image.
+ kfree(cp->mem, cp->sz);
+ cp->sz = sz;
+ cp->mem = mem;
+ mem = 0;
+
+ for(i = 0; i < elf.phnum; i++){
+ if(readi(ip, (char*)&ph, elf.phoff + i * sizeof(ph),
+ sizeof(ph)) != sizeof(ph))
+ goto bad2;
+ if(ph.type != ELF_PROG_LOAD)
+ continue;
+ if(ph.va + ph.memsz > sz)
+ goto bad2;
+ if(readi(ip, cp->mem + ph.va, ph.offset, ph.filesz) != ph.filesz)
+ goto bad2;
+ memset(cp->mem + ph.va + ph.filesz, 0, ph.memsz - ph.filesz);
+ }
+
+ iput(ip);
+
+ cp->tf->eip = elf.entry;
+ cp->tf->esp = sp;
+ setupsegs(cp);
+
+ return 0;
+
+ bad:
+ if(mem)
+ kfree(mem, sz);
+ iput(ip);
+ return -1;
+
+ bad2:
+ iput(ip);
+ proc_exit();
+ return 0;
+}