| plan 9 kernel history: overview | file list | diff list |
1999/0709/port/sysfile.c (diff list | history)
| port/sysfile.c on 1990/0227 | ||
| 1990/0227 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1990/0227 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1990/0227 | /* * The sys*() routines needn't poperror() as they return directly to syscall(). */ int | |
| 1991/0705 | newfd(Chan *c) | |
| 1990/0227 | { int i; | |
| 1997/0327 | Fgrp *f = up->fgrp; | |
| 1997/0603 | Chan **newfd, **oldfd; | |
| 1990/0227 | ||
| 1991/0705 | lock(f); | |
| 1997/0603 | for(i=0; i<f->nfd; i++) | |
| 1991/0705 | if(f->fd[i] == 0){ if(i > f->maxfd) f->maxfd = i; f->fd[i] = c; unlock(f); | |
| 1990/0227 | return i; } | |
| 1997/0603 | /* * Unbounded allocation is unwise; besides, there are only 16 bits * of fid in 9P */ if(f->nfd >= 5000){ | |
| 1997/0606 | Exhausted: | |
| 1997/0603 | unlock(f); exhausted("file descriptors"); return -1; } | |
| 1997/0606 | newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*)); if(newfd == 0) goto Exhausted; | |
| 1997/0603 | oldfd = f->fd; memmove(newfd, oldfd, f->nfd*sizeof(Chan*)); f->fd = newfd; f->nfd += DELTAFD; f->maxfd = i; f->fd[i] = c; | |
| 1991/0705 | unlock(f); | |
| 1997/0603 | free(oldfd); if(i%100 == 0) pprint("warning: process exceeds %d file descriptors\n", i); return i; | |
| 1990/0227 | } Chan* | |
| 1992/0825 | fdtochan(int fd, int mode, int chkmnt, int iref) | |
| 1990/0227 | { Chan *c; | |
| 1992/0825 | Fgrp *f; | |
| 1990/0227 | ||
| 1991/0904 | c = 0; | |
| 1993/0501 | f = up->fgrp; | |
| 1992/0825 | lock(f); | |
| 1997/0603 | if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) { | |
| 1992/0825 | unlock(f); | |
| 1990/11211 | error(Ebadfd); | |
| 1992/0825 | } if(iref) incref(c); unlock(f); if(chkmnt && (c->flag&CMSG)) { if(iref) | |
| 1997/0327 | cclose(c); | |
| 1992/0114 | error(Ebadusefd); | |
| 1992/0825 | } | |
| 1990/1009 | if(mode<0 || c->mode==ORDWR) | |
| 1990/0227 | return c; | |
| 1992/0825 | if((mode&OTRUNC) && c->mode==OREAD) { if(iref) | |
| 1997/0327 | cclose(c); | |
| 1990/11211 | error(Ebadusefd); | |
| 1992/0825 | } if((mode&~OTRUNC) != c->mode) { if(iref) | |
| 1997/0327 | cclose(c); | |
| 1991/1011 | error(Ebadusefd); | |
| 1992/0825 | } | |
| 1990/0227 | return c; } int openmode(ulong o) { | |
| 1990/08141 | o &= ~(OTRUNC|OCEXEC|ORCLOSE); | |
| 1990/0227 | if(o > OEXEC) | |
| 1991/1018 | error(Ebadarg); | |
| 1990/0227 | if(o == OEXEC) return OREAD; return o; } long | |
| 1994/0321 | sysfd2path(ulong *arg) | |
| 1993/1004 | { | |
| 1999/0629 | Chan *c; | |
| 1993/1004 | ||
| 1999/0528 | validaddr(arg[1], arg[2], 1); | |
| 1993/1004 | ||
| 1997/1205 | c = fdtochan(arg[0], -1, 0, 1); | |
| 1999/0629 | if(c->name == nil) snprint((char*)arg[1], arg[2], "<null>"); else snprint((char*)arg[1], arg[2], "%s", c->name->s); | |
| 1999/0709 | cclose(c); | |
| 1993/1004 | return 0; } long | |
| 1990/1009 | syspipe(ulong *arg) { int fd[2]; Chan *c[2]; Dev *d; | |
| 1993/0501 | Fgrp *f = up->fgrp; | |
| 1990/1009 | validaddr(arg[0], 2*BY2WD, 1); evenaddr(arg[0]); | |
| 1997/0327 | d = devtab[devno('|', 0)]; | |
| 1993/0501 | c[0] = namec("#|", Atodir, 0, 0); | |
| 1990/1009 | c[1] = 0; fd[0] = -1; fd[1] = -1; if(waserror()){ | |
| 1997/0327 | cclose(c[0]); | |
| 1990/1009 | if(c[1]) | |
| 1997/0327 | cclose(c[1]); | |
| 1990/1009 | if(fd[0] >= 0) | |
| 1991/0705 | f->fd[fd[0]]=0; | |
| 1990/1009 | if(fd[1] >= 0) | |
| 1991/0705 | f->fd[fd[1]]=0; | |
| 1990/1009 | nexterror(); } | |
| 1997/0327 | c[1] = cclone(c[0], 0); | |
| 1999/0629 | if(walkname(&c[0], "data", 1) < 0) | |
| 1998/0224 | error(Egreg); | |
| 1999/0629 | if(walkname(&c[1], "data1", 1) < 0) | |
| 1998/0224 | error(Egreg); | |
| 1997/0327 | c[0] = d->open(c[0], ORDWR); c[1] = d->open(c[1], ORDWR); | |
| 1991/0705 | fd[0] = newfd(c[0]); fd[1] = newfd(c[1]); | |
| 1990/1009 | ((long*)arg[0])[0] = fd[0]; ((long*)arg[0])[1] = fd[1]; poperror(); return 0; } long | |
| 1990/0227 | sysdup(ulong *arg) { int fd; Chan *c, *oc; | |
| 1993/0501 | Fgrp *f = up->fgrp; | |
| 1990/0227 | /* * Close after dup'ing, so date > #d/1 works */ | |
| 1992/0825 | c = fdtochan(arg[0], -1, 0, 1); | |
| 1990/0227 | fd = arg[1]; | |
| 1991/0221 | if(fd != -1){ | |
| 1997/1203 | lock(f); | |
| 1997/0603 | if(fd<0 || f->nfd<=fd) { | |
| 1997/1203 | unlock(f); | |
| 1997/0327 | cclose(c); | |
| 1991/0221 | error(Ebadfd); | |
| 1992/0825 | } | |
| 1991/0705 | if(fd > f->maxfd) f->maxfd = fd; | |
| 1992/0825 | ||
| 1991/0705 | oc = f->fd[fd]; f->fd[fd] = c; unlock(f); if(oc) | |
| 1997/0327 | cclose(oc); | |
| 1991/0706 | }else{ | |
| 1991/0705 | if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1991/0705 | nexterror(); } fd = newfd(c); poperror(); | |
| 1990/0227 | } | |
| 1991/0705 | ||
| 1990/0227 | return fd; } long sysopen(ulong *arg) { int fd; | |
| 1991/0705 | Chan *c = 0; | |
| 1990/0227 | openmode(arg[1]); /* error check only */ | |
| 1991/0706 | if(waserror()){ | |
| 1991/0705 | if(c) | |
| 1997/0327 | cclose(c); | |
| 1991/0705 | nexterror(); } | |
| 1990/0227 | validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aopen, arg[1], 0); | |
| 1991/0705 | fd = newfd(c); poperror(); | |
| 1990/0227 | return fd; } void | |
| 1991/0705 | fdclose(int fd, int flag) | |
| 1990/0227 | { int i; | |
| 1991/0705 | Chan *c; | |
| 1993/0501 | Fgrp *f = up->fgrp; | |
| 1990/0227 | ||
| 1991/0705 | lock(f); c = f->fd[fd]; | |
| 1992/0817 | if(c == 0){ /* can happen for users with shared fd tables */ unlock(f); return; } | |
| 1991/0705 | if(flag){ if(c==0 || !(c->flag&flag)){ unlock(f); return; } } f->fd[fd] = 0; if(fd == f->maxfd) for(i=fd; --i>=0 && f->fd[i]==0; ) f->maxfd = i; unlock(f); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | } long sysclose(ulong *arg) { | |
| 1992/0825 | fdtochan(arg[0], -1, 0, 0); | |
| 1991/0705 | fdclose(arg[0], 0); | |
| 1990/0227 | return 0; } long unionread(Chan *c, void *va, long n) { | |
| 1998/0829 | int i; | |
| 1990/0227 | long nr; | |
| 1992/0720 | Chan *nc; | |
| 1998/0829 | Mhead *m; Mount *mount; | |
| 1990/0227 | ||
| 1998/0829 | m = c->mh; rlock(&m->lock); mount = m->mount; for(i = 0; mount != nil && i < c->uri; i++) mount = mount->next; | |
| 1991/1011 | ||
| 1998/0901 | while(mount != nil) { | |
| 1991/1011 | if(waserror()) { | |
| 1998/0829 | runlock(&m->lock); | |
| 1991/1011 | nexterror(); } | |
| 1998/0901 | if(mount->to == nil) goto next; | |
| 1998/0829 | nc = cclone(mount->to, 0); | |
| 1991/1011 | poperror(); | |
| 1993/0318 | /* Error causes component of union to be skipped */ | |
| 1998/0512 | if(waserror()) { | |
| 1997/0327 | cclose(nc); | |
| 1992/0720 | goto next; | |
| 1991/1011 | } | |
| 1997/0327 | nc = devtab[nc->type]->open(nc, OREAD); | |
| 1991/1011 | nc->offset = c->offset; | |
| 1997/0327 | nr = devtab[nc->type]->read(nc, va, n, nc->offset); | |
| 1993/0318 | /* devdirread e.g. changes it */ | |
| 1998/0512 | c->offset = nc->offset; | |
| 1991/1011 | poperror(); | |
| 1997/0327 | cclose(nc); | |
| 1991/1011 | if(nr > 0) { | |
| 1998/0829 | runlock(&m->lock); | |
| 1991/1011 | return nr; } | |
| 1992/0720 | /* Advance to next element */ next: | |
| 1998/0829 | c->uri++; mount = mount->next; if(mount == nil) | |
| 1991/1011 | break; c->offset = 0; | |
| 1990/0227 | } | |
| 1998/0829 | runlock(&m->lock); | |
| 1991/1011 | return 0; | |
| 1990/0227 | } long | |
| 1994/0405 | sysread9p(ulong *arg) { int dir; long n; Chan *c; validaddr(arg[1], arg[2], 1); c = fdtochan(arg[0], OREAD, 1, 1); if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1994/0405 | nexterror(); } n = arg[2]; dir = c->qid.path&CHDIR; if(dir) { n -= n%DIRLEN; if(c->offset%DIRLEN || n==0) error(Etoosmall); } | |
| 1998/0829 | if(dir && c->mh) | |
| 1994/0405 | n = unionread(c, (void*)arg[1], n); | |
| 1997/0408 | else if(devtab[c->type]->dc != L'M') | |
| 1997/0327 | n = devtab[c->type]->read(c, (void*)arg[1], n, c->offset); | |
| 1994/0405 | else n = mntread9p(c, (void*)arg[1], n, c->offset); lock(c); c->offset += n; unlock(c); poperror(); | |
| 1997/0327 | cclose(c); | |
| 1994/0405 | return n; } long | |
| 1990/0227 | sysread(ulong *arg) { | |
| 1992/0825 | int dir; | |
| 1990/0227 | long n; | |
| 1992/0825 | Chan *c; | |
| 1990/0227 | ||
| 1998/0922 | n = arg[2]; validaddr(arg[1], n, 1); | |
| 1992/0825 | c = fdtochan(arg[0], OREAD, 1, 1); | |
| 1998/0922 | ||
| 1992/0825 | if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | nexterror(); } | |
| 1992/0825 | dir = c->qid.path&CHDIR; if(dir) { | |
| 1990/0227 | n -= n%DIRLEN; if(c->offset%DIRLEN || n==0) | |
| 1992/0114 | error(Etoosmall); | |
| 1990/0227 | } | |
| 1992/0825 | ||
| 1998/0829 | if(dir && c->mh) | |
| 1990/0227 | n = unionread(c, (void*)arg[1], n); else | |
| 1997/0327 | n = devtab[c->type]->read(c, (void*)arg[1], n, c->offset); | |
| 1992/0825 | lock(c); | |
| 1991/1101 | c->offset += n; | |
| 1992/0825 | unlock(c); poperror(); | |
| 1997/0327 | cclose(c); | |
| 1992/0825 | ||
| 1990/0227 | return n; } long | |
| 1994/0402 | syswrite9p(ulong *arg) { Chan *c; long n; validaddr(arg[1], arg[2], 0); c = fdtochan(arg[0], OWRITE, 1, 1); if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1994/0402 | nexterror(); } if(c->qid.path & CHDIR) error(Eisdir); | |
| 1997/0408 | if(devtab[c->type]->dc != L'M') | |
| 1997/0327 | n = devtab[c->type]->write(c, (void*)arg[1], arg[2], c->offset); | |
| 1994/0402 | else n = mntwrite9p(c, (void*)arg[1], arg[2], c->offset); lock(c); c->offset += n; unlock(c); poperror(); | |
| 1997/0327 | cclose(c); | |
| 1994/0402 | return n; } long | |
| 1990/0227 | syswrite(ulong *arg) { Chan *c; | |
| 1998/0922 | long m, n; uvlong oo; | |
| 1990/0227 | validaddr(arg[1], arg[2], 0); | |
| 1998/0922 | n = arg[2]; | |
| 1992/0825 | c = fdtochan(arg[0], OWRITE, 1, 1); if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1998/0922 | lock(c); c->offset -= n; unlock(c); | |
| 1990/0227 | nexterror(); } | |
| 1992/0825 | ||
| 1990/11211 | if(c->qid.path & CHDIR) error(Eisdir); | |
| 1992/0825 | lock(c); | |
| 1998/0922 | oo = c->offset; | |
| 1991/1101 | c->offset += n; | |
| 1992/0825 | unlock(c); | |
| 1998/0922 | m = devtab[c->type]->write(c, (void*)arg[1], n, oo); if(m < n){ lock(c); | |
| 1998/0923 | c->offset -= n - m; | |
| 1998/0922 | unlock(c); } | |
| 1992/0825 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1992/0825 | ||
| 1990/0227 | return n; } | |
| 1998/0326 | static void sseek(ulong *arg) | |
| 1990/0227 | { Chan *c; char buf[DIRLEN]; Dir dir; | |
| 1998/0319 | vlong off; union { vlong v; ulong u[2]; } o; | |
| 1990/0227 | ||
| 1998/0403 | c = fdtochan(arg[1], -1, 1, 1); if(waserror()){ cclose(c); nexterror(); } | |
| 1990/11211 | if(c->qid.path & CHDIR) error(Eisdir); | |
| 1992/0825 | ||
| 1997/0408 | if(devtab[c->type]->dc == '|') | |
| 1991/0319 | error(Eisstream); | |
| 1992/0825 | ||
| 1991/1101 | off = 0; | |
| 1998/0326 | o.u[0] = arg[2]; o.u[1] = arg[3]; switch(arg[4]){ | |
| 1990/0227 | case 0: | |
| 1998/0319 | off = o.v; c->offset = off; | |
| 1990/0227 | break; case 1: | |
| 1992/0825 | lock(c); /* lock for read/write update */ | |
| 1998/0319 | off = o.v + c->offset; c->offset = off; | |
| 1992/0825 | unlock(c); | |
| 1990/0227 | break; case 2: | |
| 1997/0327 | devtab[c->type]->stat(c, buf); | |
| 1990/0227 | convM2D(buf, &dir); | |
| 1998/0326 | off = dir.length + o.v; | |
| 1998/0319 | c->offset = off; | |
| 1990/0227 | break; } | |
| 1998/0326 | *(vlong*)arg[0] = off; | |
| 1998/0829 | c->uri = 0; | |
| 1998/0403 | cclose(c); poperror(); | |
| 1998/0319 | } long | |
| 1998/0915 | sysseek(ulong *arg) | |
| 1998/0326 | { validaddr(arg[0], BY2V, 1); sseek(arg); return 0; } long | |
| 1998/0915 | sysoseek(ulong *arg) | |
| 1998/0319 | { union { vlong v; ulong u[2]; } o; | |
| 1998/0326 | ulong a[5]; | |
| 1998/0319 | o.v = arg[1]; | |
| 1998/0326 | a[0] = (ulong)&o.v; a[1] = arg[0]; a[2] = o.u[0]; a[3] = o.u[1]; a[4] = arg[2]; sseek(a); return o.v; | |
| 1990/0227 | } long sysfstat(ulong *arg) { Chan *c; validaddr(arg[1], DIRLEN, 1); evenaddr(arg[1]); | |
| 1992/0825 | c = fdtochan(arg[0], -1, 0, 1); if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1992/0825 | nexterror(); } | |
| 1997/0327 | devtab[c->type]->stat(c, (char*)arg[1]); | |
| 1992/0825 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | return 0; } long sysstat(ulong *arg) { Chan *c; validaddr(arg[1], DIRLEN, 1); evenaddr(arg[1]); validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | nexterror(); } | |
| 1997/0327 | devtab[c->type]->stat(c, (char*)arg[1]); | |
| 1990/0227 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | return 0; } long syschdir(ulong *arg) { Chan *c; validaddr(arg[0], 1, 0); | |
| 1993/0501 | ||
| 1990/0227 | c = namec((char*)arg[0], Atodir, 0, 0); | |
| 1997/0327 | cclose(up->dot); | |
| 1993/0501 | up->dot = c; | |
| 1990/0227 | return 0; } long bindmount(ulong *arg, int ismount) { ulong flag; | |
| 1993/0501 | int fd, ret; Chan *c0, *c1, *bc; | |
| 1990/0227 | struct{ Chan *chan; char *spec; | |
| 1993/1014 | int flags; | |
| 1990/0227 | }bogus; flag = arg[2]; | |
| 1992/0607 | fd = arg[0]; | |
| 1990/0227 | if(flag>MMASK || (flag&MORDER)==(MBEFORE|MAFTER)) | |
| 1990/11211 | error(Ebadarg); | |
| 1993/0501 | ||
| 1993/1014 | bogus.flags = flag & (MRECOV|MCACHE); | |
| 1993/0501 | ||
| 1990/0227 | if(ismount){ | |
| 1993/0501 | bc = fdtochan(fd, ORDWR, 0, 1); | |
| 1992/0825 | if(waserror()) { | |
| 1997/0327 | cclose(bc); | |
| 1992/0825 | nexterror(); } bogus.chan = bc; | |
| 1990/11211 | validaddr(arg[3], 1, 0); | |
| 1991/0615 | if(vmemchr((char*)arg[3], '\0', NAMELEN) == 0) error(Ebadarg); | |
| 1992/0825 | ||
| 1990/0227 | bogus.spec = (char*)arg[3]; | |
| 1994/0622 | if(strchr(bogus.spec, ' ')) error(Ebadspec); | |
| 1992/0825 | ||
| 1990/0227 | ret = devno('M', 0); | |
| 1997/0327 | c0 = devtab[ret]->attach((char*)&bogus); | |
| 1992/0825 | poperror(); | |
| 1997/0327 | cclose(bc); | |
| 1992/0825 | } else { | |
| 1993/0501 | bogus.spec = 0; | |
| 1990/0227 | validaddr(arg[0], 1, 0); c0 = namec((char*)arg[0], Aaccess, 0, 0); } | |
| 1993/0501 | ||
| 1990/0227 | if(waserror()){ | |
| 1997/0327 | cclose(c0); | |
| 1990/0227 | nexterror(); } | |
| 1993/0501 | ||
| 1990/0227 | validaddr(arg[1], 1, 0); c1 = namec((char*)arg[1], Amount, 0, 0); if(waserror()){ | |
| 1997/0327 | cclose(c1); | |
| 1990/0227 | nexterror(); } | |
| 1993/0501 | ||
| 1997/0327 | ret = cmount(c0, c1, flag, bogus.spec); | |
| 1993/0501 | ||
| 1991/0614 | poperror(); | |
| 1997/0327 | cclose(c1); | |
| 1991/0614 | poperror(); | |
| 1997/0327 | cclose(c0); | |
| 1991/0705 | if(ismount) | |
| 1992/0607 | fdclose(fd, 0); | |
| 1990/0227 | return ret; } long sysbind(ulong *arg) { return bindmount(arg, 0); } long sysmount(ulong *arg) { return bindmount(arg, 1); } long | |
| 1991/1011 | sysunmount(ulong *arg) { Chan *cmount, *cmounted; cmounted = 0; validaddr(arg[1], 1, 0); cmount = namec((char *)arg[1], Amount, 0, 0); if(arg[0]) { if(waserror()) { | |
| 1997/0327 | cclose(cmount); | |
| 1991/1011 | nexterror(); } validaddr(arg[0], 1, 0); | |
| 1993/1111 | cmounted = namec((char*)arg[0], Aopen, OREAD, 0); | |
| 1991/1011 | poperror(); } if(waserror()) { | |
| 1997/0327 | cclose(cmount); | |
| 1991/1011 | if(cmounted) | |
| 1997/0327 | cclose(cmounted); | |
| 1991/1011 | nexterror(); } | |
| 1997/0327 | cunmount(cmount, cmounted); cclose(cmount); | |
| 1991/1011 | if(cmounted) | |
| 1997/0327 | cclose(cmounted); | |
| 1998/0512 | poperror(); | |
| 1991/1011 | return 0; } long | |
| 1990/0227 | syscreate(ulong *arg) { int fd; | |
| 1991/0705 | Chan *c = 0; | |
| 1990/0227 | openmode(arg[1]); /* error check only */ | |
| 1991/0705 | if(waserror()) { if(c) | |
| 1997/0327 | cclose(c); | |
| 1991/0705 | nexterror(); } | |
| 1990/0227 | validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Acreate, arg[1], arg[2]); | |
| 1991/0705 | fd = newfd(c); poperror(); | |
| 1990/0227 | return fd; } long sysremove(ulong *arg) { Chan *c; validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ | |
| 1990/0703 | c->type = 0; /* see below */ | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | nexterror(); } | |
| 1997/0327 | devtab[c->type]->remove(c); | |
| 1990/0227 | /* * 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; | |
| 1991/0614 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | return 0; } long syswstat(ulong *arg) { Chan *c; validaddr(arg[1], DIRLEN, 0); | |
| 1991/1107 | nameok((char*)arg[1]); | |
| 1990/0227 | validaddr(arg[0], 1, 0); c = namec((char*)arg[0], Aaccess, 0, 0); if(waserror()){ | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | nexterror(); } | |
| 1997/0327 | devtab[c->type]->wstat(c, (char*)arg[1]); | |
| 1990/0227 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | return 0; } long sysfwstat(ulong *arg) { Chan *c; validaddr(arg[1], DIRLEN, 0); | |
| 1991/1107 | nameok((char*)arg[1]); | |
| 1992/0825 | c = fdtochan(arg[0], -1, 1, 1); if(waserror()) { | |
| 1997/0327 | cclose(c); | |
| 1992/0825 | nexterror(); } | |
| 1997/0327 | devtab[c->type]->wstat(c, (char*)arg[1]); | |
| 1992/0825 | poperror(); | |
| 1997/0327 | cclose(c); | |
| 1990/0227 | return 0; } | |