diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/unix/drawterm/kern/sysfile.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/unix/drawterm/kern/sysfile.c')
-rwxr-xr-x | sys/src/cmd/unix/drawterm/kern/sysfile.c | 1244 |
1 files changed, 1244 insertions, 0 deletions
diff --git a/sys/src/cmd/unix/drawterm/kern/sysfile.c b/sys/src/cmd/unix/drawterm/kern/sysfile.c new file mode 100755 index 000000000..18dadbcda --- /dev/null +++ b/sys/src/cmd/unix/drawterm/kern/sysfile.c @@ -0,0 +1,1244 @@ +#include "u.h" +#include "lib.h" +#include "dat.h" +#include "fns.h" +#include "error.h" + +#include "user.h" +#undef open +#undef mount +#undef read +#undef write +#undef seek +#undef stat +#undef wstat +#undef remove +#undef close +#undef fstat +#undef fwstat + +/* + * The sys*() routines needn't poperror() as they return directly to syscall(). + */ + +static void +unlockfgrp(Fgrp *f) +{ + int ex; + + ex = f->exceed; + f->exceed = 0; + unlock(&f->ref.lk); + if(ex) + pprint("warning: process exceeds %d file descriptors\n", ex); +} + +int +growfd(Fgrp *f, int fd) /* fd is always >= 0 */ +{ + Chan **newfd, **oldfd; + + if(fd < f->nfd) + return 0; + if(fd >= f->nfd+DELTAFD) + return -1; /* out of range */ + /* + * Unbounded allocation is unwise; besides, there are only 16 bits + * of fid in 9P + */ + if(f->nfd >= 5000){ + Exhausted: + print("no free file descriptors\n"); + return -1; + } + newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*)); + if(newfd == 0) + goto Exhausted; + oldfd = f->fd; + memmove(newfd, oldfd, f->nfd*sizeof(Chan*)); + f->fd = newfd; + free(oldfd); + f->nfd += DELTAFD; + if(fd > f->maxfd){ + if(fd/100 > f->maxfd/100) + f->exceed = (fd/100)*100; + f->maxfd = fd; + } + return 1; +} + +/* + * this assumes that the fgrp is locked + */ +int +findfreefd(Fgrp *f, int start) +{ + int fd; + + for(fd=start; fd<f->nfd; fd++) + if(f->fd[fd] == 0) + break; + if(fd >= f->nfd && growfd(f, fd) < 0) + return -1; + return fd; +} + +int +newfd(Chan *c) +{ + int fd; + Fgrp *f; + + f = up->fgrp; + lock(&f->ref.lk); + fd = findfreefd(f, 0); + if(fd < 0){ + unlockfgrp(f); + return -1; + } + if(fd > f->maxfd) + f->maxfd = fd; + f->fd[fd] = c; + unlockfgrp(f); + return fd; +} + +int +newfd2(int fd[2], Chan *c[2]) +{ + Fgrp *f; + + f = up->fgrp; + lock(&f->ref.lk); + fd[0] = findfreefd(f, 0); + if(fd[0] < 0){ + unlockfgrp(f); + return -1; + } + fd[1] = findfreefd(f, fd[0]+1); + if(fd[1] < 0){ + unlockfgrp(f); + return -1; + } + if(fd[1] > f->maxfd) + f->maxfd = fd[1]; + f->fd[fd[0]] = c[0]; + f->fd[fd[1]] = c[1]; + unlockfgrp(f); + + return 0; +} + +Chan* +fdtochan(int fd, int mode, int chkmnt, int iref) +{ + Chan *c; + Fgrp *f; + + c = 0; + f = up->fgrp; + + lock(&f->ref.lk); + if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) { + unlock(&f->ref.lk); + error(Ebadfd); + } + if(iref) + incref(&c->ref); + unlock(&f->ref.lk); + + if(chkmnt && (c->flag&CMSG)) { + if(iref) + cclose(c); + error(Ebadusefd); + } + + if(mode<0 || c->mode==ORDWR) + return c; + + if((mode&OTRUNC) && c->mode==OREAD) { + if(iref) + cclose(c); + error(Ebadusefd); + } + + if((mode&~OTRUNC) != c->mode) { + if(iref) + cclose(c); + error(Ebadusefd); + } + + return c; +} + +int +openmode(ulong o) +{ + o &= ~(OTRUNC|OCEXEC|ORCLOSE); + if(o > OEXEC) + error(Ebadarg); + if(o == OEXEC) + return OREAD; + return o; +} + +long +_sysfd2path(int fd, char *buf, uint nbuf) +{ + Chan *c; + + c = fdtochan(fd, -1, 0, 1); + + if(c->name == nil) + snprint(buf, nbuf, "<null>"); + else + snprint(buf, nbuf, "%s", c->name->s); + cclose(c); + return 0; +} + +long +_syspipe(int fd[2]) +{ + Chan *c[2]; + Dev *d; + static char *datastr[] = {"data", "data1"}; + + d = devtab[devno('|', 0)]; + c[0] = namec("#|", Atodir, 0, 0); + c[1] = 0; + fd[0] = -1; + fd[1] = -1; + + if(waserror()){ + cclose(c[0]); + if(c[1]) + cclose(c[1]); + nexterror(); + } + c[1] = cclone(c[0]); + if(walk(&c[0], datastr+0, 1, 1, nil) < 0) + error(Egreg); + if(walk(&c[1], datastr+1, 1, 1, nil) < 0) + error(Egreg); + c[0] = d->open(c[0], ORDWR); + c[1] = d->open(c[1], ORDWR); + if(newfd2(fd, c) < 0) + error(Enofd); + poperror(); + + return 0; +} + +long +_sysdup(int fd0, int fd1) +{ + int fd; + Chan *c, *oc; + Fgrp *f = up->fgrp; + + /* + * Close after dup'ing, so date > #d/1 works + */ + c = fdtochan(fd0, -1, 0, 1); + fd = fd1; + if(fd != -1){ + lock(&f->ref.lk); + if(fd<0 || growfd(f, fd)<0) { + unlockfgrp(f); + cclose(c); + error(Ebadfd); + } + if(fd > f->maxfd) + f->maxfd = fd; + + oc = f->fd[fd]; + f->fd[fd] = c; + unlockfgrp(f); + if(oc) + cclose(oc); + }else{ + if(waserror()) { + cclose(c); + nexterror(); + } + fd = newfd(c); + if(fd < 0) + error(Enofd); + poperror(); + } + + return fd; +} + +long +_sysopen(char *name, int mode) +{ + int fd; + Chan *c = 0; + + openmode(mode); /* error check only */ + if(waserror()){ + if(c) + cclose(c); + nexterror(); + } + c = namec(name, Aopen, mode, 0); + fd = newfd(c); + if(fd < 0) + error(Enofd); + poperror(); + return fd; +} + +void +fdclose(int fd, int flag) +{ + int i; + Chan *c; + Fgrp *f = up->fgrp; + + lock(&f->ref.lk); + c = f->fd[fd]; + if(c == 0){ + /* can happen for users with shared fd tables */ + unlock(&f->ref.lk); + return; + } + if(flag){ + if(c==0 || !(c->flag&flag)){ + unlock(&f->ref.lk); + return; + } + } + f->fd[fd] = 0; + if(fd == f->maxfd) + for(i=fd; --i>=0 && f->fd[i]==0; ) + f->maxfd = i; + + unlock(&f->ref.lk); + cclose(c); +} + +long +_sysclose(int fd) +{ + fdtochan(fd, -1, 0, 0); + fdclose(fd, 0); + + return 0; +} + +long +unionread(Chan *c, void *va, long n) +{ + int i; + long nr; + Mhead *m; + Mount *mount; + + qlock(&c->umqlock); + m = c->umh; + rlock(&m->lock); + mount = m->mount; + /* bring mount in sync with c->uri and c->umc */ + for(i = 0; mount != nil && i < c->uri; i++) + mount = mount->next; + + nr = 0; + while(mount != nil) { + /* Error causes component of union to be skipped */ + if(mount->to && !waserror()) { + if(c->umc == nil){ + c->umc = cclone(mount->to); + c->umc = devtab[c->umc->type]->open(c->umc, OREAD); + } + + nr = devtab[c->umc->type]->read(c->umc, va, n, c->umc->offset); + c->umc->offset += nr; + poperror(); + } + if(nr > 0) + break; + + /* Advance to next element */ + c->uri++; + if(c->umc) { + cclose(c->umc); + c->umc = nil; + } + mount = mount->next; + } + runlock(&m->lock); + qunlock(&c->umqlock); + return nr; +} + +static long +kread(int fd, void *buf, long n, vlong *offp) +{ + int dir; + Chan *c; + vlong off; + + c = fdtochan(fd, OREAD, 1, 1); + + if(waserror()) { + cclose(c); + nexterror(); + } + + dir = c->qid.type&QTDIR; + /* + * The offset is passed through on directories, normally. sysseek complains but + * pread is used by servers and e.g. exportfs that shouldn't need to worry about this issue. + */ + + if(offp == nil) /* use and maintain channel's offset */ + off = c->offset; + else + off = *offp; + + if(off < 0) + error(Enegoff); + + if(dir && c->umh) + n = unionread(c, buf, n); + else + n = devtab[c->type]->read(c, buf, n, off); + + if(offp == nil){ + lock(&c->ref.lk); + c->offset += n; + unlock(&c->ref.lk); + } + + poperror(); + cclose(c); + + return n; +} + +/* name conflicts with netbsd +long +_sys_read(int fd, void *buf, long n) +{ + return kread(fd, buf, n, nil); +} +*/ + +long +_syspread(int fd, void *buf, long n, vlong off) +{ + if(off == ((uvlong) ~0)) + return kread(fd, buf, n, nil); + return kread(fd, buf, n, &off); +} + +static long +kwrite(int fd, void *buf, long nn, vlong *offp) +{ + Chan *c; + long m, n; + vlong off; + + n = 0; + c = fdtochan(fd, OWRITE, 1, 1); + if(waserror()) { + if(offp == nil){ + lock(&c->ref.lk); + c->offset -= n; + unlock(&c->ref.lk); + } + cclose(c); + nexterror(); + } + + if(c->qid.type & QTDIR) + error(Eisdir); + + n = nn; + + if(offp == nil){ /* use and maintain channel's offset */ + lock(&c->ref.lk); + off = c->offset; + c->offset += n; + unlock(&c->ref.lk); + }else + off = *offp; + + if(off < 0) + error(Enegoff); + + m = devtab[c->type]->write(c, buf, n, off); + + if(offp == nil && m < n){ + lock(&c->ref.lk); + c->offset -= n - m; + unlock(&c->ref.lk); + } + + poperror(); + cclose(c); + + return m; +} + +long +sys_write(int fd, void *buf, long n) +{ + return kwrite(fd, buf, n, nil); +} + +long +_syspwrite(int fd, void *buf, long n, vlong off) +{ + if(off == ((uvlong) ~0)) + return kwrite(fd, buf, n, nil); + return kwrite(fd, buf, n, &off); +} + +static vlong +_sysseek(int fd, vlong off, int whence) +{ + Chan *c; + uchar buf[sizeof(Dir)+100]; + Dir dir; + int n; + + c = fdtochan(fd, -1, 1, 1); + if(waserror()){ + cclose(c); + nexterror(); + } + if(devtab[c->type]->dc == '|') + error(Eisstream); + + switch(whence){ + case 0: + if((c->qid.type & QTDIR) && off != 0) + error(Eisdir); + if(off < 0) + error(Enegoff); + c->offset = off; + break; + + case 1: + if(c->qid.type & QTDIR) + error(Eisdir); + lock(&c->ref.lk); /* lock for read/write update */ + off = off + c->offset; + if(off < 0) + error(Enegoff); + c->offset = off; + unlock(&c->ref.lk); + break; + + case 2: + if(c->qid.type & QTDIR) + error(Eisdir); + n = devtab[c->type]->stat(c, buf, sizeof buf); + if(convM2D(buf, n, &dir, nil) == 0) + error("internal error: stat error in seek"); + off = dir.length + off; + if(off < 0) + error(Enegoff); + c->offset = off; + break; + + default: + error(Ebadarg); + } + c->uri = 0; + c->dri = 0; + cclose(c); + poperror(); + return off; +} + +void +validstat(uchar *s, int n) +{ + int m; + char buf[64]; + + if(statcheck(s, n) < 0) + error(Ebadstat); + /* verify that name entry is acceptable */ + s += STATFIXLEN - 4*BIT16SZ; /* location of first string */ + /* + * s now points at count for first string. + * if it's too long, let the server decide; this is + * only for his protection anyway. otherwise + * we'd have to allocate and waserror. + */ + m = GBIT16(s); + s += BIT16SZ; + if(m+1 > sizeof buf) + return; + memmove(buf, s, m); + buf[m] = '\0'; + /* name could be '/' */ + if(strcmp(buf, "/") != 0) + validname(buf, 0); +} + +long +_sysfstat(int fd, void *buf, long n) +{ + Chan *c; + uint l; + + l = n; + validaddr(buf, l, 1); + c = fdtochan(fd, -1, 0, 1); + if(waserror()) { + cclose(c); + nexterror(); + } + l = devtab[c->type]->stat(c, buf, l); + poperror(); + cclose(c); + return l; +} + +long +_sysstat(char *name, void *buf, long n) +{ + Chan *c; + uint l; + + l = n; + validaddr(buf, l, 1); + validaddr(name, 1, 0); + c = namec(name, Aaccess, 0, 0); + if(waserror()){ + cclose(c); + nexterror(); + } + l = devtab[c->type]->stat(c, buf, l); + poperror(); + cclose(c); + return l; +} + +long +_syschdir(char *name) +{ + Chan *c; + + validaddr(name, 1, 0); + + c = namec(name, Atodir, 0, 0); + cclose(up->dot); + up->dot = c; + return 0; +} + +long +bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec) +{ + int ret; + Chan *c0, *c1, *ac, *bc; + struct{ + Chan *chan; + Chan *authchan; + char *spec; + int flags; + }bogus; + + if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER)) + error(Ebadarg); + + bogus.flags = flag & MCACHE; + + if(ismount){ + if(up->pgrp->noattach) + error(Enoattach); + + ac = nil; + bc = fdtochan(fd, ORDWR, 0, 1); + if(waserror()) { + if(ac) + cclose(ac); + cclose(bc); + nexterror(); + } + + if(afd >= 0) + ac = fdtochan(afd, ORDWR, 0, 1); + + bogus.chan = bc; + bogus.authchan = ac; + + validaddr((ulong)spec, 1, 0); + bogus.spec = spec; + if(waserror()) + error(Ebadspec); + validname(spec, 1); + poperror(); + + ret = devno('M', 0); + c0 = devtab[ret]->attach((char*)&bogus); + + poperror(); + if(ac) + cclose(ac); + cclose(bc); + }else{ + bogus.spec = 0; + validaddr((ulong)arg0, 1, 0); + c0 = namec(arg0, Abind, 0, 0); + } + + if(waserror()){ + cclose(c0); + nexterror(); + } + + validaddr((ulong)arg1, 1, 0); + c1 = namec(arg1, Amount, 0, 0); + if(waserror()){ + cclose(c1); + nexterror(); + } + + ret = cmount(&c0, c1, flag, bogus.spec); + + poperror(); + cclose(c1); + poperror(); + cclose(c0); + if(ismount) + fdclose(fd, 0); + + return ret; +} + +long +_sysbind(char *old, char *new, int flag) +{ + return bindmount(0, -1, -1, old, new, flag, nil); +} + +long +_sysmount(int fd, int afd, char *new, int flag, char *spec) +{ + return bindmount(1, fd, afd, nil, new, flag, spec); +} + +long +_sysunmount(char *old, char *new) +{ + Chan *cmount, *cmounted; + + cmounted = 0; + + cmount = namec(new, Amount, 0, 0); + + if(old) { + if(waserror()) { + cclose(cmount); + nexterror(); + } + validaddr(old, 1, 0); + /* + * This has to be namec(..., Aopen, ...) because + * if arg[0] is something like /srv/cs or /fd/0, + * opening it is the only way to get at the real + * Chan underneath. + */ + cmounted = namec(old, Aopen, OREAD, 0); + poperror(); + } + + if(waserror()) { + cclose(cmount); + if(cmounted) + cclose(cmounted); + nexterror(); + } + + cunmount(cmount, cmounted); + cclose(cmount); + if(cmounted) + cclose(cmounted); + poperror(); + return 0; +} + +long +_syscreate(char *name, int mode, ulong perm) +{ + int fd; + Chan *c = 0; + + openmode(mode&~OEXCL); /* error check only; OEXCL okay here */ + if(waserror()) { + if(c) + cclose(c); + nexterror(); + } + validaddr(name, 1, 0); + c = namec(name, Acreate, mode, perm); + fd = newfd(c); + if(fd < 0) + error(Enofd); + poperror(); + return fd; +} + +long +_sysremove(char *name) +{ + Chan *c; + + c = namec(name, Aremove, 0, 0); + if(waserror()){ + c->type = 0; /* see below */ + cclose(c); + nexterror(); + } + devtab[c->type]->remove(c); + /* + * Remove clunks the fid, but we need to recover the Chan + * so fake it up. rootclose() is known to be a nop. + */ + c->type = 0; + poperror(); + cclose(c); + return 0; +} + +long +_syswstat(char *name, void *buf, long n) +{ + Chan *c; + uint l; + + l = n; + validstat(buf, l); + validaddr(name, 1, 0); + c = namec(name, Aaccess, 0, 0); + if(waserror()){ + cclose(c); + nexterror(); + } + l = devtab[c->type]->wstat(c, buf, l); + poperror(); + cclose(c); + return l; +} + +long +_sysfwstat(int fd, void *buf, long n) +{ + Chan *c; + uint l; + + l = n; + validaddr(buf, l, 0); + validstat(buf, l); + c = fdtochan(fd, -1, 1, 1); + if(waserror()) { + cclose(c); + nexterror(); + } + l = devtab[c->type]->wstat(c, buf, l); + poperror(); + cclose(c); + return l; +} + + +static void +starterror(void) +{ + assert(up->nerrlab == 0); +} + +static void +_syserror(void) +{ + char *p; + + p = up->syserrstr; + up->syserrstr = up->errstr; + up->errstr = p; +} + +static void +enderror(void) +{ + assert(up->nerrlab == 1); + poperror(); +} + +int +sysbind(char *old, char *new, int flag) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysbind(old, new, flag); + enderror(); + return n; +} + +int +syschdir(char *path) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syschdir(path); + enderror(); + return n; +} + +int +sysclose(int fd) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysclose(fd); + enderror(); + return n; +} + +int +syscreate(char *name, int mode, ulong perm) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syscreate(name, mode, perm); + enderror(); + return n; +} + +int +sysdup(int fd0, int fd1) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysdup(fd0, fd1); + enderror(); + return n; +} + +int +sysfstat(int fd, uchar *buf, int n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysfstat(fd, buf, n); + enderror(); + return n; +} + +int +sysfwstat(int fd, uchar *buf, int n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysfwstat(fd, buf, n); + enderror(); + return n; +} + +int +sysmount(int fd, int afd, char *new, int flag, char *spec) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysmount(fd, afd, new, flag, spec); + enderror(); + return n; +} + +int +sysunmount(char *old, char *new) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysunmount(old, new); + enderror(); + return n; +} + +int +sysopen(char *name, int mode) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysopen(name, mode); + enderror(); + return n; +} + +int +syspipe(int *fd) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syspipe(fd); + enderror(); + return n; +} + +long +syspread(int fd, void *buf, long n, vlong off) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syspread(fd, buf, n, off); + enderror(); + return n; +} + +long +syspwrite(int fd, void *buf, long n, vlong off) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syspwrite(fd, buf, n, off); + enderror(); + return n; +} + +long +sysread(int fd, void *buf, long n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syspread(fd, buf, n, (uvlong) ~0); + enderror(); + return n; +} + +int +sysremove(char *path) +{ + int n; + + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysremove(path); + enderror(); + return n; +} + +vlong +sysseek(int fd, vlong off, int whence) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + off = _sysseek(fd, off, whence); + enderror(); + return off; +} + +int +sysstat(char *name, uchar *buf, int n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _sysstat(name, buf, n); + enderror(); + return n; +} + +long +syswrite(int fd, void *buf, long n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syspwrite(fd, buf, n, (uvlong) ~0); + enderror(); + return n; +} + +int +syswstat(char *name, uchar *buf, int n) +{ + starterror(); + if(waserror()){ + _syserror(); + return -1; + } + n = _syswstat(name, buf, n); + enderror(); + return n; +} + +void +werrstr(char *f, ...) +{ + char buf[ERRMAX]; + va_list arg; + + va_start(arg, f); + vsnprint(buf, sizeof buf, f, arg); + va_end(arg); + + if(up->nerrlab) + strecpy(up->errstr, up->errstr+ERRMAX, buf); + else + strecpy(up->syserrstr, up->syserrstr+ERRMAX, buf); +} + +int +__errfmt(Fmt *fmt) +{ + if(up->nerrlab) + return fmtstrcpy(fmt, up->errstr); + else + return fmtstrcpy(fmt, up->syserrstr); +} + +int +errstr(char *buf, uint n) +{ + char tmp[ERRMAX]; + char *p; + + p = up->nerrlab ? up->errstr : up->syserrstr; + memmove(tmp, p, ERRMAX); + utfecpy(p, p+ERRMAX, buf); + utfecpy(buf, buf+n, tmp); + return strlen(buf); +} + +int +rerrstr(char *buf, uint n) +{ + char *p; + + p = up->nerrlab ? up->errstr : up->syserrstr; + utfecpy(buf, buf+n, p); + return strlen(buf); +} + +void* +_sysrendezvous(void* arg0, void* arg1) +{ + void *tag, *val; + Proc *p, **l; + + tag = arg0; + l = &REND(up->rgrp, (uintptr)tag); + up->rendval = (void*)~0; + + lock(&up->rgrp->ref.lk); + for(p = *l; p; p = p->rendhash) { + if(p->rendtag == tag) { + *l = p->rendhash; + val = p->rendval; + p->rendval = arg1; + + while(p->mach != 0) + ; + procwakeup(p); + unlock(&up->rgrp->ref.lk); + return val; + } + l = &p->rendhash; + } + + /* Going to sleep here */ + up->rendtag = tag; + up->rendval = arg1; + up->rendhash = *l; + *l = up; + up->state = Rendezvous; + unlock(&up->rgrp->ref.lk); + + procsleep(); + + return up->rendval; +} + +void* +sysrendezvous(void *tag, void *val) +{ + void *n; + + starterror(); + if(waserror()){ + _syserror(); + return (void*)~0; + } + n = _sysrendezvous(tag, val); + enderror(); + return n; +} |