ref: 3866717cbb020199d58171c1c0cdd7382a74ee82
dir: /emu/port/inferno.c/
#include "dat.h"
#include "fns.h"
#include "error.h"
#include "interp.h"
#include "isa.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->r);
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 = osmillisec();
}
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("");
}
osenter();
*f->ret = limbosleep(f->period);
osleave();
poperror();
}
acquire();
}
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->l);
/* 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->r);
nfg->fd[fd] = c;
if(nfg->maxfd < fd)
nfg->maxfd = fd;
}
}
}
unlock(&ofg->l);
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;
}