ref: c8e25d2a18c0395431abc5818a1d2f0561b0181f
dir: /sys/src/games/v8e/sys.c/
#include <u.h> #include <libc.h> #include "dat.h" #include "fns.h" Chan chans[NCHANS]; int systrace=1; #define dprint print static u32int arg(int n) { return memread32(r[12] + (n + 1) * 4); } static char * strget(u32int addr) { int n; char *s; for(n = 0; memread8(addr + n) != 0; n++) ; s = emalloc(n + 1); for(n = 0; n == 0 || s[n-1] != 0; n++) s[n] = memread8(addr + n); return s; } static char ** vecget(u32int addr) { int n; u32int u; char **s; for(n = 0; readm(addr + n, 2) != 0; n += 4) ; s = emalloc((n + 1) * sizeof(char *)); for(n = 0; u = readm(addr + n * 4, 2), u != 0; n++) s[n] = strget(u); return s; } static Chan * getfd(int n) { if((unsigned)n >= NCHANS || chans[n].fd < 0) return nil; return &chans[n]; } static Chan * newfd(void) { Chan *c; for(c = chans; c < chans + nelem(chans); c++) if(c->fd < 0) return c; return nil; } static int toerrno(void) { char buf[ERRMAX]; rerrstr(buf, sizeof(buf)); if(strstr(buf, "not found")) return -ENOENT; print("couldn't translate %s\n", buf); return -EIO; } static int toerrnoi(int rc) { if(rc >= 0) return rc; return toerrno(); } static int dostat(u32int buf, Dir *d) { int m; if(d == nil) return toerrno(); writem(buf, 0, 1); /* dev */ writem(buf + 2, d->qid.path, 1); /* ino */ m = d->mode & 0777; if((d->mode & DMDIR) != 0) m |= 040000; else m |= 010000; writem(buf + 4, m, 1); /* mode */ writem(buf + 6, 1, 1); /* nlink */ writem(buf + 8, 0, 1); /* uid */ writem(buf + 10, 0, 1); /* gid */ writem(buf + 12, d->dev, 1); /* dev */ writem(buf + 16, d->length, 2); /* size */ writem(buf + 20, d->atime, 2); /* atime */ writem(buf + 24, d->mtime, 2); /* mtime */ writem(buf + 28, d->mtime, 2); /* ctime */ free(d); return 0; } static int sysexit(void) { int no; no = arg(0); if(no == 0) exits(nil); exits(smprint("%d", no)); return 0; } static int dodirread(Chan *c) { Dir *d, *dp; int rc; free(c->buf); c->buf = c->bufp = c->bufe = nil; rc = dirread(c->fd, &d); if(rc <= 0) return rc; c->bufp = c->bufe = c->buf = emalloc(16 * rc); for(dp = d; --rc >= 0; dp++){ *c->bufe++ = dp->qid.path; *c->bufe++ = dp->qid.path >> 8; strncpy(c->bufe, dp->name, 14); c->bufe += 14; } free(d); return 0; } static int sysread(void) { int fd, sz, rc, i; u32int addr; char *buf; Chan *c; fd = arg(0); addr = arg(1); sz = arg(2); if(systrace) dprint("read(%d, %#ux, %d)\n", fd, addr, sz); c = getfd(fd); if(sz < 0) return -EINVAL; if(c == nil) return -EBADF; if((c->flags & DIR) != 0){ if(c->bufp >= c->bufe) if(dodirread(c) < 0) return toerrno(); for(rc = 0; sz > 0 && c->bufp < c->bufe; rc++, sz--) writem(addr++, *c->bufp++, 0); return rc; }else{ buf = emalloc(sz); rc = read(c->fd, buf, sz); for(i = 0; i < rc; i++) writem(addr + i, buf[i], 0); free(buf); if(rc < 0) return toerrno(); } return rc; } static int syswrite(void) { int fd, sz, rc, i; u32int addr; Chan *c; char *buf; fd = arg(0); addr = arg(1); sz = arg(2); if(systrace) dprint("write(%d, %#ux, %d)\n", fd, addr, sz); c = getfd(fd); if(sz < 0) return -EINVAL; if(c == nil) return -EBADF; buf = emalloc(sz); for(i = 0; i < sz; i++) buf[i] = memread8(addr + i); rc = write(c->fd, buf, sz); free(buf); return toerrnoi(rc); } static int sysopen(void) { char *s; Chan *c; int m; Dir *d; s = strget(arg(0)); m = arg(1); if(systrace) dprint("open(\"%s\", %#uo)\n", s, m); switch(m){ case 0: m = OREAD; break; case 1: m = OWRITE; break; case 2: m = ORDWR; break; default: free(s); return -EINVAL; } c = newfd(); if(c == nil){ free(s); return -EMFILE; } c->fd = open(s, m); free(s); if(c->fd < 0) return toerrno(); d = dirfstat(c->fd); if(d == nil){ close(c->fd); return toerrno(); } if((d->mode & DMDIR) != 0) c->flags |= DIR; free(d); return c - chans; } static int sysclose(void) { int fd; Chan *c; fd = arg(0); if(systrace) dprint("close(%d)\n", fd); c = getfd(fd); if(c == nil) return -EBADF; if((c->flags & DONTCLOSE) == 0) close(c->fd); c->fd = -1; return 0; } static int sysfstat(void) { int fd, buf; Chan *c; Dir *d; fd = arg(0); buf = arg(1); if(systrace) dprint("fstat(%d, %#ux)\n", fd, buf); c = getfd(fd); if(c == nil) return -EBADF; d = dirfstat(c->fd); return dostat(buf, d); } static int syslstat(void) { char *s; int buf; Dir *d; s = strget(arg(0)); buf = arg(1); if(systrace) dprint("lstat(\"%s\", %#ux)\n", s, buf); d = dirstat(s); free(s); return dostat(buf, d); } static int sysioctl(void) { int fd, ctl; u32int addr; Chan *c; fd = arg(0); ctl = arg(1); addr = arg(2); if(systrace) dprint("lstat(%d, %#ux, %#ux)\n", fd, ctl, addr); c = getfd(fd); if(c == nil) return -EBADF; switch(ctl){ case 't'<<8|8: if((c->flags & FAKETTY) != 0){ writem(addr, 13 | 13<<8 | '#'<<16 | '@'<<24, 2); writem(addr + 4, 06010, 2); return 0; } return -ENOTTY; case 'j'<<8|3: return -EINVAL; default: fprint(2, "unknown ioctl %c%d\n", ctl >> 8, (u8int)ctl); return -EINVAL; } } static int systime(void) { u32int addr; int t; addr = arg(0); if(systrace) dprint("time(%#ux)\n", addr); t = time(0); if(addr != 0) writem(addr, t, 2); return t; } static int sysbreak(void) { u32int a; int ns; a = arg(0); if(systrace) dprint("break(%#ux)\n", a); a = -(-a & -1024); ns = a - segs[1].start; if(ns > segs[1].size){ segs[1].data = realloc(segs[1].data, ns); memset((uchar *) segs[1].data + segs[1].size, 0, ns - segs[1].size); segs[1].size = ns; } return 0; } static int sysftime(void) { u32int p; vlong n; Tm *t; p = arg(0); if(systrace) dprint("ftime(%#ux)\n", p); n = nsec(); n /= 1000000; writem(p + 4, n % 1000, 1); n /= 1000; writem(p, n, 2); t = localtime(n); writem(p + 6, -t->tzoff / 60, 1); writem(p + 8, 0, 1); return 0; } static int syssignal(void) { return 0; } static int sysgetpid(void) { if(systrace) dprint("getpid()\n"); return getpid() & 0xffff; } static int sysaccess(void) { char *s; int m, rc; s = strget(arg(0)); m = arg(1); if(systrace) dprint("access(\"%s\", %#ux)\n", s, m); rc = access(s, m & 7); free(s); return toerrnoi(rc); } static int syscreat(void) { char *s; Chan *c; int m; s = strget(arg(0)); m = arg(1); if(systrace) dprint("creat(\"%s\", %#uo)\n", s, m); c = newfd(); if(c == nil){ free(s); return -EMFILE; } c->fd = create(s, OWRITE, m & 0777); free(s); if(c->fd < 0) return toerrno(); return c - chans; } static int sysseek(void) { int fd, off, wh; Chan *c; fd = arg(0); off = arg(1); wh = arg(2); if(systrace) dprint("seek(%d, %d, %d)\n", fd, off, wh); c = getfd(fd); if(c == nil || off < 0 || (uint)wh > 2) return -EBADF; return toerrnoi(seek(c->fd, off, wh)); } static int sysunlink(void) { char *s; int rc; s = strget(arg(0)); if(systrace) dprint("unlink(\"%s\")\n", s); rc = remove(s); free(s); return toerrnoi(rc); } static int syschdir(void) { char *s; int rc; s = strget(arg(0)); if(systrace) dprint("chdir(\"%s\")\n", s); rc = chdir(s); free(s); return toerrnoi(rc); } static int sysgetuid(void) { return 0; } static int sysfork(void) { int rc; if(systrace) dprint("fork()\n"); rc = fork(); if(rc < 0) return toerrno(); if(rc == 0){ r[1] = 1; return getppid(); } r[1] = 0; return rc; } static int sysexece(void) { char *file, **argv, **env, **p; int rc; file = strget(arg(0)); argv = vecget(arg(1)); env = vecget(arg(2)); if(systrace) dprint("exece(\"%s\", ..., ...)\n", file); rc = load(file, argv, env); for(p = argv; *p != nil; p++) free(*p); for(p = env; *p != nil; p++) free(*p); free(file); free(argv); free(env); return toerrnoi(rc); } static int syswait(void) { Waitmsg *w; int rc, st; u32int addr; char *p; addr = arg(0); if(systrace) dprint("wait(%#ux)\n", addr); w = wait(); if(w == nil) return toerrno(); rc = w->pid; if(addr != 0){ st = strtol(w->msg, &p, 10) & 255 << 8; if(*p == 0) st = 127 << 8; writem(addr, st, 2); } free(w); return rc; } int mask = 022; static int sysumask(void) { int rc; rc = mask; mask = arg(0); if(systrace) dprint("umask(%#uo)\n", mask); return rc; } static int syslink(void) { char *a, *b; int f0, f1, rc, n; char buf[8192]; a = strget(arg(0)); b = strget(arg(1)); if(systrace) dprint("link(\"%s\", \"%s\")\n", a, b); f0 = open(a, OREAD); f1 = create(b, OWRITE | OEXCL, 0777 ^ mask); if(f0 < 0 || f1 < 0) { err: rc = toerrno(); goto out; } for(;;){ n = read(f0, buf, sizeof(buf)); if(n < 0) goto err; if(n == 0) break; if(write(f1, buf, n) < n) goto err; } rc = 0; out: if(f0 >= 0) close(f0); if(f1 >= 0) close(f1); free(a); free(b); return rc; } static int syschmod(void) { char *a; int mode; Dir d; Dir *e; a = strget(arg(0)); mode = arg(1); if(systrace) dprint("chmod(\"%s\", %#uo)\n", a, mode); e = dirstat(a); if(e == nil){ free(a); return toerrno(); } nulldir(&d); d.mode = e->mode & ~0777 | mode & 0777; free(e); if(dirwstat(a, &d) < 0){ free(a); return toerrno(); } free(a); return 0; } static int sysdup(void) { int fd; Chan *c, *d; fd = arg(0); if(systrace) dprint("dup(%d)\n", fd); c = getfd(fd); if(c == nil) return -EBADF; d = newfd(); if(d == nil) return -EMFILE; d->fd = c->fd; d->flags = c->flags; return d - chans; } void syscall(u16int c) { int rc; static int (*calls[])(void) = { [1] sysexit, [2] sysfork, [3] sysread, [4] syswrite, [5] sysopen, [6] sysclose, [7] syswait, [8] syscreat, [9] syslink, [10] sysunlink, [12] syschdir, [13] systime, [15] syschmod, [17] sysbreak, [18] syslstat, [19] sysseek, [20] sysgetpid, [24] sysgetuid, [28] sysfstat, [33] sysaccess, [35] sysftime, [40] syslstat, [41] sysdup, [48] syssignal, [54] sysioctl, [59] sysexece, [60] sysumask, [66] sysfork, }; if(c >= nelem(calls) || calls[c] == nil) sysfatal("unknown syscall %d", c); rc = calls[c](); if(rc < 0){ r[0] = -rc; ps |= 1; }else{ r[0] = rc; ps &= ~1; } } void sysinit(void) { int i; for(i = 0; i < NCHANS; i++) chans[i].fd = -1; chans[0].fd = 0; chans[0].flags = DONTCLOSE|FAKETTY; chans[1].fd = 1; chans[1].flags = DONTCLOSE|FAKETTY; chans[2].fd = 2; chans[2].flags = DONTCLOSE|FAKETTY; }