#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "isa.h" #include "interp.h" #include "runt.h" #include "kernel.h" /* * here because Sys_FileIO is not public */ extern int srvf2c(char*, char*, Sys_FileIO*); /* * System types connected to gc */ uchar FDmap[] = Sys_FD_map; uchar FileIOmap[] = Sys_FileIO_map; void freeFD(Heap*, int); void freeFileIO(Heap*, int); Type* TFD; Type* TFileIO; static uchar rmap[] = Sys_FileIO_read_map; static uchar wmap[] = Sys_FileIO_write_map; static Type* FioTread; static Type* FioTwrite; static uchar dmap[] = Sys_Dir_map; static Type* Tdir; typedef struct FD FD; struct FD { Sys_FD fd; Fgrp* grp; }; void sysinit(void) { TFD = dtype(freeFD, sizeof(FD), FDmap, sizeof(FDmap)); TFileIO = dtype(freeFileIO, Sys_FileIO_size, FileIOmap, sizeof(FileIOmap)); /* Support for devsrv.c */ FioTread = dtype(freeheap, Sys_FileIO_read_size, rmap, sizeof(rmap)); FioTwrite = dtype(freeheap, Sys_FileIO_write_size, wmap, sizeof(wmap)); /* Support for dirread */ Tdir = dtype(freeheap, Sys_Dir_size, dmap, sizeof(dmap)); } void freeFD(Heap *h, int swept) { FD *handle; USED(swept); handle = H2D(FD*, h); release(); if(handle->fd.fd >= 0) kfgrpclose(handle->grp, handle->fd.fd); closefgrp(handle->grp); acquire(); } void freeFileIO(Heap *h, int swept) { Sys_FileIO *fio; if(swept) return; fio = H2D(Sys_FileIO*, h); destroy(fio->read); destroy(fio->write); } Sys_FD* mkfd(int fd) { Heap *h; Fgrp *fg; FD *handle; h = heap(TFD); handle = H2D(FD*, h); handle->fd.fd = fd; fg = up->env->fgrp; handle->grp = fg; incref(fg); return (Sys_FD*)handle; } #define fdchk(x) ((x) == (Sys_FD*)H ? -1 : (x)->fd) void seterror(char *err, ...) { char *estr; va_list arg; estr = up->env->errstr; va_start(arg, err); vseprint(estr, estr+ERRMAX, err, arg); va_end(arg); } char* syserr(char *s, char *es, Prog *p) { Osenv *o; o = p->osenv; kstrcpy(s, o->errstr, es - s); return s + strlen(s); } void Sys_millisec(void *fp) { F_Sys_millisec *f; f = fp; *f->ret = TK2MS(MACHP(0)->ticks); } void Sys_open(void *fp) { int fd; F_Sys_open *f; f = fp; destroy(*f->ret); *f->ret = H; release(); fd = kopen(string2c(f->s), f->mode); acquire(); if(fd == -1) return; *f->ret = mkfd(fd); } void Sys_pipe(void *fp) { Array *a; int fd[2]; Sys_FD **sfd; F_Sys_pipe *f; f = fp; *f->ret = -1; a = f->fds; if(a->len < 2) return; if(kpipe(fd) < 0) return; sfd = (Sys_FD**)a->data; destroy(sfd[0]); destroy(sfd[1]); sfd[0] = H; sfd[1] = H; sfd[0] = mkfd(fd[0]); sfd[1] = mkfd(fd[1]); *f->ret = 0; } void Sys_fildes(void *fp) { F_Sys_fildes *f; int fd; f = fp; destroy(*f->ret); *f->ret = H; release(); fd = kdup(f->fd, -1); acquire(); if(fd == -1) return; *f->ret = mkfd(fd); } void Sys_dup(void *fp) { F_Sys_dup *f; f = fp; release(); *f->ret = kdup(f->old, f->new); acquire(); } void Sys_create(void *fp) { int fd; F_Sys_create *f; f = fp; destroy(*f->ret); *f->ret = H; release(); fd = kcreate(string2c(f->s), f->mode, f->perm); acquire(); if(fd == -1) return; *f->ret = mkfd(fd); } void Sys_remove(void *fp) { F_Sys_remove *f; f = fp; release(); *f->ret = kremove(string2c(f->s)); acquire(); } void Sys_seek(void *fp) { F_Sys_seek *f; f = fp; release(); *f->ret = kseek(fdchk(f->fd), f->off, f->start); acquire(); } void Sys_unmount(void *fp) { F_Sys_unmount *f; f = fp; release(); *f->ret = kunmount(string2c(f->s1), string2c(f->s2)); acquire(); } void Sys_read(void *fp) { int n; F_Sys_read *f; f = fp; n = f->n; if(f->buf == (Array*)H || n < 0) { *f->ret = 0; return; } if(n > f->buf->len) n = f->buf->len; release(); *f->ret = kread(fdchk(f->fd), f->buf->data, n); acquire(); } void Sys_readn(void *fp) { int fd, m, n, t; F_Sys_readn *f; f = fp; n = f->n; if(f->buf == (Array*)H || n < 0) { *f->ret = 0; return; } if(n > f->buf->len) n = f->buf->len; fd = fdchk(f->fd); release(); for(t = 0; t < n; t += m){ m = kread(fd, (char*)f->buf->data+t, n-t); if(m <= 0){ if(t == 0) t = m; break; } } *f->ret = t; acquire(); } void Sys_pread(void *fp) { int n; F_Sys_pread *f; f = fp; n = f->n; if(f->buf == (Array*)H || n < 0) { *f->ret = 0; return; } if(n > f->buf->len) n = f->buf->len; release(); *f->ret = kpread(fdchk(f->fd), f->buf->data, n, f->off); acquire(); } void Sys_chdir(void *fp) { F_Sys_chdir *f; f = fp; release(); *f->ret = kchdir(string2c(f->path)); acquire(); } void Sys_write(void *fp) { int n; F_Sys_write *f; f = fp; n = f->n; if(f->buf == (Array*)H || n < 0) { *f->ret = 0; return; } if(n > f->buf->len) n = f->buf->len; release(); *f->ret = kwrite(fdchk(f->fd), f->buf->data, n); acquire(); } void Sys_pwrite(void *fp) { int n; F_Sys_pwrite *f; f = fp; n = f->n; if(f->buf == (Array*)H || n < 0) { *f->ret = 0; return; } if(n > f->buf->len) n = f->buf->len; release(); *f->ret = kpwrite(fdchk(f->fd), f->buf->data, n, f->off); acquire(); } static void unpackdir(Dir *d, Sys_Dir *sd) { retstr(d->name, &sd->name); retstr(d->uid, &sd->uid); retstr(d->gid, &sd->gid); retstr(d->muid, &sd->muid); sd->qid.path = d->qid.path; sd->qid.vers = d->qid.vers; sd->qid.qtype = d->qid.type; sd->mode = d->mode; sd->atime = d->atime; sd->mtime = d->mtime; sd->length = d->length; sd->dtype = d->type; sd->dev = d->dev; } static Dir* packdir(Sys_Dir *sd) { char *nm[4], *p; int i, n; Dir *d; nm[0] = string2c(sd->name); nm[1] = string2c(sd->uid); nm[2] = string2c(sd->gid); nm[3] = string2c(sd->muid); n = 0; for(i=0; i<4; i++) n += strlen(nm[i])+1; d = smalloc(sizeof(*d)+n); p = (char*)d+sizeof(*d); for(i=0; i<4; i++){ n = strlen(nm[i])+1; memmove(p, nm[i], n); nm[i] = p; p += n; } d->name = nm[0]; d->uid = nm[1]; d->gid = nm[2]; d->muid = nm[3]; d->qid.path = sd->qid.path; d->qid.vers = sd->qid.vers; d->qid.type = sd->qid.qtype; d->mode = sd->mode; d->atime = sd->atime; d->mtime = sd->mtime; d->length = sd->length; d->type = sd->dtype; d->dev = sd->dev; return d; } void Sys_fstat(void *fp) { Dir *d; F_Sys_fstat *f; f = fp; f->ret->t0 = -1; release(); d = kdirfstat(fdchk(f->fd)); acquire(); if(d == nil) return; if(waserror() == 0){ unpackdir(d, &f->ret->t1); f->ret->t0 = 0; poperror(); } free(d); } void Sys_stat(void *fp) { Dir *d; F_Sys_stat *f; f = fp; f->ret->t0 = -1; release(); d = kdirstat(string2c(f->s)); acquire(); if(d == nil) return; if(waserror() == 0){ unpackdir(d, &f->ret->t1); f->ret->t0 = 0; poperror(); } free(d); } void Sys_fd2path(void *fp) { F_Sys_fd2path *f; char *s; void *r; f = fp; r = *f->ret; *f->ret = H; destroy(r); release(); s = kfd2path(fdchk(f->fd)); acquire(); if(waserror() == 0){ retstr(s, f->ret); poperror(); } free(s); } void Sys_mount(void *fp) { F_Sys_mount *f; f = fp; release(); *f->ret = kmount(fdchk(f->fd), fdchk(f->afd), string2c(f->on), f->flags, string2c(f->spec)); acquire(); } void Sys_bind(void *fp) { F_Sys_bind *f; f = fp; release(); *f->ret = kbind(string2c(f->s), string2c(f->on), f->flags); acquire(); } void Sys_wstat(void *fp) { Dir *d; F_Sys_wstat *f; f = fp; d = packdir(&f->d); release(); *f->ret = kdirwstat(string2c(f->s), d); acquire(); free(d); } void Sys_fwstat(void *fp) { Dir *d; F_Sys_fwstat *f; f = fp; d = packdir(&f->d); release(); *f->ret = kdirfwstat(fdchk(f->fd), d); acquire(); free(d); } void Sys_print(void *fp) { int n; Prog *p; Chan *c; char buf[1024], *b = buf; F_Sys_print *f; f = fp; c = up->env->fgrp->fd[1]; if(c == nil) return; p = currun(); release(); n = xprint(p, f, &f->vargs, f->s, buf, sizeof(buf)); if (n >= sizeof(buf)-UTFmax-2) n = bigxprint(p, f, &f->vargs, f->s, &b, sizeof(buf)); *f->ret = kwrite(1, b, n); if (b != buf) free(b); acquire(); } void Sys_fprint(void *fp) { int n; Prog *p; char buf[1024], *b = buf; F_Sys_fprint *f; f = fp; p = currun(); release(); n = xprint(p, f, &f->vargs, f->s, buf, sizeof(buf)); if (n >= sizeof(buf)-UTFmax-2) n = bigxprint(p, f, &f->vargs, f->s, &b, sizeof(buf)); *f->ret = kwrite(fdchk(f->fd), b, n); if (b != buf) free(b); acquire(); } void Sys_werrstr(void *fp) { F_Sys_werrstr *f; f = fp; *f->ret = 0; kstrcpy(up->env->errstr, string2c(f->s), ERRMAX); } void Sys_dial(void *fp) { int cfd; char dir[NETPATHLEN], *a, *l; F_Sys_dial *f; f = fp; a = string2c(f->addr); l = string2c(f->local); release(); f->ret->t0 = kdial(a, l, dir, &cfd); acquire(); destroy(f->ret->t1.dfd); f->ret->t1.dfd = H; destroy(f->ret->t1.cfd); f->ret->t1.cfd = H; if(f->ret->t0 == -1) return; f->ret->t1.dfd = mkfd(f->ret->t0); f->ret->t0 = 0; f->ret->t1.cfd = mkfd(cfd); retstr(dir, &f->ret->t1.dir); } void Sys_announce(void *fp) { char dir[NETPATHLEN], *a; F_Sys_announce *f; f = fp; a = string2c(f->addr); release(); f->ret->t0 = kannounce(a, dir); acquire(); destroy(f->ret->t1.dfd); f->ret->t1.dfd = H; destroy(f->ret->t1.cfd); f->ret->t1.cfd = H; if(f->ret->t0 == -1) return; f->ret->t1.cfd = mkfd(f->ret->t0); f->ret->t0 = 0; retstr(dir, &f->ret->t1.dir); } void Sys_listen(void *fp) { F_Sys_listen *f; char dir[NETPATHLEN], *d; f = fp; d = string2c(f->c.dir); release(); f->ret->t0 = klisten(d, dir); acquire(); destroy(f->ret->t1.dfd); f->ret->t1.dfd = H; destroy(f->ret->t1.cfd); f->ret->t1.cfd = H; if(f->ret->t0 == -1) return; f->ret->t1.cfd = mkfd(f->ret->t0); f->ret->t0 = 0; retstr(dir, &f->ret->t1.dir); } void Sys_sleep(void *fp) { F_Sys_sleep *f; f = fp; release(); if(f->period > 0){ if(waserror()){ acquire(); error(""); } tsleep(&up->sleep, return0, 0, f->period); poperror(); } acquire(); *f->ret = 0; } void Sys_stream(void *fp) { Prog *p; uchar *buf; int src, dst; F_Sys_stream *f; int nbytes, t, n; f = fp; buf = malloc(f->bufsiz); if(buf == nil) { kwerrstr(Enomem); *f->ret = -1; return; } src = fdchk(f->src); dst = fdchk(f->dst); p = currun(); release(); t = 0; nbytes = 0; while(p->kill == nil) { n = kread(src, buf+t, f->bufsiz-t); if(n <= 0) break; t += n; if(t >= f->bufsiz) { if(kwrite(dst, buf, t) != t) { t = 0; break; } nbytes += t; t = 0; } } if(t != 0) { kwrite(dst, buf, t); nbytes += t; } acquire(); free(buf); *f->ret = nbytes; } void Sys_export(void *fp) { F_Sys_export *f; f = fp; release(); *f->ret = export(fdchk(f->c), string2c(f->dir), f->flag&Sys_EXPASYNC); acquire(); } void Sys_file2chan(void *fp) { int r; Heap *h; Channel *c; Sys_FileIO *fio; F_Sys_file2chan *f; void *sv; h = heap(TFileIO); fio = H2D(Sys_FileIO*, h); c = cnewc(FioTread, movtmp, 16); fio->read = c; c = cnewc(FioTwrite, movtmp, 16); fio->write = c; f = fp; sv = *f->ret; *f->ret = fio; destroy(sv); release(); r = srvf2c(string2c(f->dir), string2c(f->file), fio); acquire(); if(r == -1) { *f->ret = H; destroy(fio); } } enum { /* the following pctl calls can block and must release the virtual machine */ BlockingPctl= Sys_NEWFD|Sys_FORKFD|Sys_NEWNS|Sys_FORKNS|Sys_NEWENV|Sys_FORKENV }; void Sys_pctl(void *fp) { int fd; Prog *p; List *l; Chan *c; volatile struct {Pgrp *np;} np; Pgrp *opg; Chan *dot; Osenv *o; F_Sys_pctl *f; Fgrp *fg, *ofg, *nfg; volatile struct {Egrp *ne;} ne; Egrp *oe; f = fp; p = currun(); if(f->flags & BlockingPctl) release(); np.np = nil; ne.ne = nil; if(waserror()) { closepgrp(np.np); closeegrp(ne.ne); if(f->flags & BlockingPctl) acquire(); *f->ret = -1; return; } o = p->osenv; if(f->flags & Sys_NEWFD) { ofg = o->fgrp; nfg = newfgrp(ofg); lock(ofg); /* file descriptors to preserve */ for(l = f->movefd; l != H; l = l->tail) { fd = *(int*)l->data; if(fd >= 0 && fd <= ofg->maxfd) { c = ofg->fd[fd]; if(c != nil && fd < nfg->nfd && nfg->fd[fd] == nil) { incref(c); nfg->fd[fd] = c; if(nfg->maxfd < fd) nfg->maxfd = fd; } } } unlock(ofg); o->fgrp = nfg; closefgrp(ofg); } else if(f->flags & Sys_FORKFD) { ofg = o->fgrp; fg = dupfgrp(ofg); /* file descriptors to close */ for(l = f->movefd; l != H; l = l->tail) kclose(*(int*)l->data); o->fgrp = fg; closefgrp(ofg); } if(f->flags & Sys_NEWNS) { np.np = newpgrp(); dot = o->pgrp->dot; np.np->dot = cclone(dot); np.np->slash = cclone(dot); cnameclose(np.np->slash->name); np.np->slash->name = newcname("/"); np.np->nodevs = o->pgrp->nodevs; opg = o->pgrp; o->pgrp = np.np; np.np = nil; closepgrp(opg); } else if(f->flags & Sys_FORKNS) { np.np = newpgrp(); pgrpcpy(np.np, o->pgrp); opg = o->pgrp; o->pgrp = np.np; np.np = nil; closepgrp(opg); } if(f->flags & Sys_NEWENV) { oe = o->egrp; o->egrp = newegrp(); closeegrp(oe); } else if(f->flags & Sys_FORKENV) { ne.ne = newegrp(); egrpcpy(ne.ne, o->egrp); oe = o->egrp; o->egrp = ne.ne; ne.ne = nil; closeegrp(oe); } if(f->flags & Sys_NEWPGRP) newgrp(p); if(f->flags & Sys_NODEVS) o->pgrp->nodevs = 1; poperror(); if(f->flags & BlockingPctl) acquire(); *f->ret = p->pid; } void Sys_dirread(void *fp) { Dir *b; int i, n; Heap *h; uchar *d; void *r; F_Sys_dirread *f; f = fp; f->ret->t0 = -1; r = f->ret->t1; f->ret->t1 = H; destroy(r); release(); n = kdirread(fdchk(f->fd), &b); acquire(); if(n <= 0) { f->ret->t0 = n; free(b); return; } if(waserror()){ free(b); return; } h = heaparray(Tdir, n); poperror(); d = H2D(Array*, h)->data; for(i = 0; i < n; i++) { unpackdir(b+i, (Sys_Dir*)d); d += Sys_Dir_size; } f->ret->t0 = n; f->ret->t1 = H2D(Array*, h); free(b); } void Sys_fauth(void *fp) { int fd; F_Sys_fauth *f; void *r; f = fp; r = *f->ret; *f->ret = H; destroy(r); release(); fd = kfauth(fdchk(f->fd), string2c(f->aname)); acquire(); if(fd >= 0) *f->ret = mkfd(fd); } void Sys_fversion(void *fp) { void *r; F_Sys_fversion *f; int n; char buf[20], *s; f = fp; f->ret->t0 = -1; r = f->ret->t1; f->ret->t1 = H; destroy(r); s = string2c(f->version); n = strlen(s); if(n >= sizeof(buf)-1) n = sizeof(buf)-1; memmove(buf, s, n); buf[n] = 0; release(); n = kfversion(fdchk(f->fd), f->msize, buf, sizeof(buf)); acquire(); if(n >= 0){ f->ret->t0 = f->msize; retnstr(buf, n, &f->ret->t1); } } void Sys_iounit(void *fp) { F_Sys_iounit *f; f = fp; release(); *f->ret = kiounit(fdchk(f->fd)); acquire(); } void ccom(Progq **cl, Prog *p) { volatile struct {Progq **cl;} vcl; cqadd(cl, p); vcl.cl = cl; if(waserror()) { if(p->ptr != nil) { /* no killcomm */ cqdelp(vcl.cl, p); p->ptr = nil; } nexterror(); } cblock(p); poperror(); } void crecv(Channel *c, void *ip) { Prog *p; REG rsav; if(c->send->prog == nil && c->size == 0) { p = currun(); p->ptr = ip; ccom(&c->recv, p); return; } rsav = R; R.s = &c; R.d = ip; irecv(); R = rsav; } void csend(Channel *c, void *ip) { Prog *p; REG rsav; if(c->recv->prog == nil && (c->buf == H || c->size == c->buf->len)) { p = currun(); p->ptr = ip; ccom(&c->send, p); return; } rsav = R; R.s = ip; R.d = &c; isend(); R = rsav; }