V8/usr/sys/sys/neta.c
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/inode.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/stat.h"
#include "../h/neta.h"
#include "../h/mount.h"
#include "../h/buf.h"
#include "../h/stream.h"
#include "../h/trace.h"
#include "../h/file.h"
extern struct stdata *stenter();
struct senda nilx;
#define ND 100
struct {
char len, s, n;
struct senda x[ND];
struct rcva y[ND];
} netabuf = {ND};
#define addx(z) netabuf.x[netabuf.n] = *z; netabuf.s = 1;
#define addy(z) netabuf.y[netabuf.n++] = *z; if(netabuf.n >= ND) netabuf.n = 0; netabuf.s = 0;
namount()
{ struct a {
int fstyp;
int unqname;
int flag; /* 0 = mount, 1 = unmount */
int cfd;
char *freg;
} *uap = (struct a *)u.u_ap;
if(!suser())
return;
if(minor(uap->unqname)) { /* minor device numbers used by server */
u.u_error = ENXIO;
return;
}
if (uap->flag)
naunmount(uap->fstyp, uap->unqname);
else
nadomount(uap->fstyp, uap->unqname, uap->cfd, uap->freg);
}
nadomount(fstyp, dev, cfd, freg)
dev_t dev;
char *freg;
{
struct inode *cip, *dip;
struct mount *mp;
struct file *fp;
/* convert cfd to the inode with the stream */
fp = getf(cfd);
if(u.u_error)
return;
cip = fp->f_inode;
if(cip->i_sptr == NULL) {
u.u_error = ENXIO;
return;
}
/* convert the mt point to an inode */
u.u_dirp = (caddr_t)freg;
dip = namei(uchar, 0, 1);
if(dip == NULL) {
u.u_error = EBUSY;
return;
}
if((dip->i_mode & IFMT) != IFDIR) {
iput(dip);
u.u_error = EBUSY;
return;
}
/* find a mount struct */
mp = allocmount(fstyp, dev);
if (mp == NULL) {
iput(dip);
u.u_error = EBUSY;
return;
}
mp->m_inodp = dip;
mp->m_idev = cip;
dip->i_flag |= IMOUNT;
cip->i_count++;
cip->i_un.i_key = 0;
prele(cip);
prele(dip);
}
naunmount(fstyp, dev)
int fstyp;
dev_t dev;
{
struct inode *ip;
struct mount *mp; /* should we send unmount mesg? */
mp = findmount(fstyp, dev);
if (mp == NULL) {
u.u_error = EINVAL;
return;
}
xumount(dev); /* shared text from remote root */
for(ip = inode; ip < inodeNINODE; ip++)
if(ip->i_number != 0 && ip->i_fstyp == fstyp
&& major(ip->i_dev) == major(dev)) {
xumount(ip->i_dev); /* others, one at a time */
u.u_error = EBUSY;
return;
}
ip = mp->m_inodp;
ip->i_flag &= ~IMOUNT;
plock(ip);
iput(ip);
if(mp->m_idev)
stclose(mp->m_idev, 1);
iput(mp->m_idev);
freemount(mp);
}
naput(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
trace(NPUT, ip->i_number, trannum);
if(ip->i_flag & ICHG)
naupdat(ip, &time, &time, 0);
x = nilx;
x.trannum = trannum;
x.cmd = NPUT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno)
u.u_error = y.errno;
}
struct inode *
naget(fstyp, dev, ino, ip)
dev_t dev;
struct inode *ip;
{ struct mount *mp;
struct senda x;
struct rcva y;
if(ino == 0) { /* this must be a disaster of some sort */
if(!u.u_error)
u.u_error = EMFILE; /* just in case for nanami */
printf("naget ino 0 dev %d\n", ip->i_dev);
iput(ip);
return(0);
}
trace(NGET, ip->i_number, trannum);
for(mp = mount; mp < mount + NMOUNT; mp++) {
if(mp->m_fstyp != fstyp)
continue;
if(mp->m_dev != (dev & ~0xff)) /* minor devs used by server */
continue;
ip->i_un.i_cip = mp->m_idev;
ip->i_dev = dev;
goto found;
}
u.u_error = EMFILE;
iput(ip);
return(0);
found:
x = nilx;
x.trannum = trannum;
x.cmd = NGET;
x.uid = u.u_uid;
x.dev = dev;
x.ino = ino;
send(ip->i_un.i_cip, &x, &y);
if(y.errno == 0) {
ip->i_mode = y.mode;
ip->i_un.i_tag = y.tag;
ip->i_nlink = y.nlink;
ip->i_size = y.size;
ip->i_uid = y.uid;
ip->i_gid = y.gid;
return(ip);
}
iput(ip);
u.u_error = y.errno;
return(0);
}
nafree(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
trace(NFREE, ip->i_number, trannum);
x = nilx;
x.trannum = trannum;
x.cmd = NFREE;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno)
u.u_error = y.errno;
}
/* this is used by CREAT */
naupdat(ip, ta, tm, waitfor)
struct inode *ip;
time_t *ta, *tm;
{ struct senda x;
struct rcva y;
trace(NUPDAT, ip->i_number, trannum);
x = nilx;
x.trannum = trannum;
x.cmd = NUPDAT;
x.uid = u.u_uid;
x.gid = u.u_gid;
x.newuid = ip->i_uid;
x.newgid = ip->i_gid;
x.mode = ip->i_mode;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
if(ip->i_flag & IACC)
x.ta = *ta;
else
x.ta = 0;
if(ip->i_flag & ICHG)
x.tm = *tm;
else
x.tm = 0;
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
return;
}
ip->i_mode = y.mode;
ip->i_nlink = y.nlink;
ip->i_size = y.size;
ip->i_uid = y.uid;
ip->i_gid = y.gid;
ip->i_flag &= ~(IUPD|IACC|ICHG);
}
naread(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
struct buf *bp;
int n;
trace(NREAD, ip->i_number, trannum);
bp = geteblk();
clrbuf(bp); /* could use user's buffer */
x = nilx;
x.trannum = trannum;
x.cmd = NREAD;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
x.buf = bp->b_un.b_addr;
do {
n = u.u_count;
if(n > BUFSIZE)
n = BUFSIZE;
x.count = n;
x.offset = u.u_offset;
send(ip->i_un.i_cip, &x, &y);
if((n = y.count) > 0) {
if(u.u_segflg != 1) {
if(copyout(bp->b_un.b_addr, u.u_base, n)) {
u.u_error = EFAULT;
break;
}
}
else
bcopy(bp->b_un.b_addr, u.u_base, n);
u.u_base += n;
u.u_offset += n;
u.u_count -= n;
}
if(y.errno)
u.u_error = y.errno;
} while(u.u_error == 0 && u.u_count != 0 && n > 0);
brelse(bp);
}
nawrite(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
struct buf *bp;
int n;
trace(NWRT, ip->i_number, trannum);
bp = geteblk();
x = nilx;
x.trannum = trannum;
x.cmd = NWRT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
x.buf = bp->b_un.b_addr;
do {
n = u.u_count;
if(n > BUFSIZE) /* should be bufsiz, but ... */
n = BUFSIZE;
if(u.u_segflg != 1) {
if(copyin(u.u_base, bp->b_un.b_addr, n)) {
u.u_error = EFAULT;
break;
}
}
else
bcopy(u.u_base, bp->b_un.b_addr, n);
x.count = n;
x.offset = u.u_offset;
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
break;
}
ip->i_flag |= IUPD|ICHG;
u.u_count -= n;
u.u_offset += n;
u.u_base += n;
} while(u.u_error == 0 && u.u_count != 0);
brelse(bp);
}
natrunc(ip)
struct inode *ip;
{ struct senda x;
struct rcva y;
trace(NTRUNC, ip->i_number, trannum);
x = nilx;
x.trannum = trannum;
x.cmd = NTRUNC;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno)
u.u_error = y.errno;
}
nastat(ip, ub, adj)
struct inode *ip;
struct stat *ub;
off_t adj;
{ struct senda x;
struct rcva y;
struct stat ds;
trace(NSTAT, ip->i_number, trannum);
x = nilx;
x.trannum = trannum;
x.cmd = NSTAT;
x.uid = u.u_uid;
x.tag = ip->i_un.i_tag;
x.dev = ip->i_dev;
x.ino = ip->i_number;
send(ip->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
return;
}
ds.st_dev = ip->i_dev;
ds.st_ino = ip->i_number;
ip->i_mode = ds.st_mode = y.mode;
ip->i_nlink = ds.st_nlink = y.nlink;
ip->i_uid = ds.st_uid = y.uid;
ip->i_gid = ds.st_gid = y.gid;
ds.st_size = y.size - adj;
ds.st_atime = y.tm[0];
ds.st_mtime = y.tm[1];
ds.st_ctime = y.tm[2];
if(copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
u.u_error = EFAULT;
}
/* a lot like fsnami */
nanami(p, pflagp, follow)
struct nx *p;
struct argnamei **pflagp;
{ register struct inode *dp, *dip;
register char *cp;
register struct buf *bp, *nbp;
register struct direct *ep;
int i, fstyp;
dev_t d;
ino_t ino;
struct argnamei *flagp = *pflagp;
struct senda x;
struct rcva y;
trace(NNAMI, 0, trannum);
cp = p->cp;
dp = p->dp;
x = nilx;
x.cmd = NNAMI;
x.uid = u.u_uid;
x.gid = u.u_gid;
/*
* dp must be a directory and
* must have X permission.
* cp is a path name relative to that directory.
*/
dirloop:
if((dp->i_mode&IFMT) != IFDIR)
u.u_error = ENOTDIR;
(void) access(dp, IEXEC);
for (i=0; *cp!='\0' && *cp!='/'; i++) {
if (i >= DIRSIZ) {
u.u_error = ENOENT;
break;
}
u.u_dbuf[i] = *cp++;
}
if(u.u_error)
goto out;
while (i < DIRSIZ)
u.u_dbuf[i++] = '\0';
if (u.u_dbuf[0] == '\0') { /* null name, e.g. "/" or "" */
if (flagp) {
u.u_error = ENOENT;
goto out;
}
goto out1;
}
u.u_segflg = 1;
/* send off the request, get back ino, dev, flagp stuff */
x.trannum = trannum;
x.tag = dp->i_un.i_tag;
x.dev = dp->i_dev;
x.ino = dp->i_number;
x.count = DIRSIZ;
x.buf = u.u_dbuf;
while(*cp == '/')
cp++;
if(flagp) {
if(*cp != 0)
goto noflag;
switch(flagp->flag) {
case NI_DEL:
x.flags = NDEL;
break;
case NI_LINK:
x.flags = NLINK;
x.dev = flagp->idev;
x.ino = flagp->ino;
break;
case NI_CREAT:
case NI_NXCREAT:
x.flags = NCREAT;
x.mode = flagp->mode & ~u.u_cmask;
break;
}
}
noflag:
send(dp->i_un.i_cip, &x, &y);
if(y.errno) {
u.u_error = y.errno;
goto out;
}
if(y.flags == NOMATCH)
goto nomatch;
u.u_dent.d_ino = y.ino;
d = y.dev;
if(flagp && flagp->flag == NI_DEL && *cp == 0) {
/* delete the entry, server did all but xrele */
if(dp->i_number == u.u_dent.d_ino) /* for '.' */
goto out;
else
dip = ifind(d, u.u_dent.d_ino, dp->i_fstyp);
if(dip == NULL)
goto out;
if(u.u_dent.d_ino == 0)
printf("nanami ino = 0 before iget\n");
else {
dip = iget(d, u.u_dent.d_ino, dp->i_fstyp); /* to lock it */
if(dip->i_flag&ITEXT)
xrele(dip); /* free busy text */
dip->i_nlink--;
dip->i_flag |= ICHG;
iput(dip);
}
goto out;
}
/*
* Special handling for ".."
*/
ino = dp->i_number;
fstyp = dp->i_fstyp;
if(y.flags == NROOT) { /* popped out of net fs */
if (dp == u.u_rdir)
u.u_dent.d_ino = dp->i_number;
else if (u.u_dent.d_ino==ROOTINO && dp->i_number == ROOTINO) {
for(i=1; i<NMOUNT; i++)
if(mount[i].m_fstyp == fstyp &&
mount[i].m_dev == dp->i_dev) {
iput(dp);
dp = mount[i].m_inodp;
plock(dp);
dp->i_count++;
/* was there always .. there? */
if(*cp && cp < p->nbp->b_un.b_addr + 3)
panic("nanami");
if(!*cp && cp < p->nbp->b_un.b_addr + 2)
panic("nanami2");
if(*cp)
*--cp = '/';
*--cp = '.';
*--cp = '.';
if(fstyp != dp->i_fstyp)
goto more;
goto dirloop;
}
}
}
if(ino != u.u_dent.d_ino || dp->i_dev != d) { /* avoid extra put */
iput(dp);
if(u.u_dent.d_ino == 0) {
printf("nanami ino is 0\n");
dp = 0;
}
else
dp = iget(d, u.u_dent.d_ino, fstyp);
}
if(dp == NULL)
goto out1;
if(fstyp != dp->i_fstyp)
goto more;
/*
* Check for symbolic link
*/
if ((dp->i_mode&IFMT)==IFLNK && (follow || *cp)) {
char *ocp;
ocp = cp;
while (*cp++)
;
if (dp->i_size + (cp-ocp) >= BSIZE(dp->i_dev)-1
|| ++p->nlink>8) {
u.u_error = ELOOP;
goto out;
}
bcopy(ocp, p->nbp->b_un.b_addr+dp->i_size + 1, cp-ocp);
*(p->nbp->b_un.b_addr + dp->i_size) = '/';
u.u_base = p->nbp->b_un.b_addr;
u.u_count = dp->i_size;
u.u_offset = 0;
readi(dp);
if(u.u_error)
goto out;
cp = p->nbp->b_un.b_addr;
iput(dp);
if (*cp == '/') {
while (*cp == '/')
cp++;
if ((dp = u.u_rdir) == NULL)
dp = rootdir;
plock(dp);
dp->i_count++;
} else {
if(ino == 0) {
printf("nanami ino 0 in dir\n");
dp = 0;
}
else
dp = iget(d, ino, fstyp); /* retrieve original directory */
if (dp == NULL) /* how can this happen? */
goto out1;
}
if(fstyp != dp->i_fstyp)
goto more;
goto dirloop;
}
if(*cp)
goto dirloop;
goto out1;
nomatch:
/*
* Search failed.
*/
if(flagp) { /* probably creating a new file */
switch(flagp->flag) {
case NI_LINK: /* make a link */
goto out;
case NI_CREAT: /* create a new file */
case NI_NXCREAT:
if(y.errno == EACCES || y.ino == 0) {
u.u_error = EACCES;
goto out;
}
dip = iget(y.dev, y.ino, dp->i_fstyp);
if(dip == NULL)
goto out;
iput(dp);
dp = dip;
flagp->ino = dip->i_number;
*pflagp = 0;
goto out1;
}
}
u.u_error = ENOENT;
out:
p->dp = dp;
return(1);
out1:
p->dp = dp;
return(0);
more:
p->dp = dp;
p->cp = cp;
return(2);
}
struct {
int tran;
short proc, dev;
} ntx[32]; /* more debuggery */
send(cip, x, y)
struct inode *cip;
struct senda *x;
struct rcva *y;
{ int n, tn, ix;
x->version = NETVERSION;
/* until demux works, use key as a lock */
while(cip->i_un.i_key)
sleep((caddr_t)cip, PZERO);
cip->i_un.i_key = 1;
trannum++; /* uniqueness */
tn = x->trannum;
netabuf.s = 2;
for(ix = 0; ntx[ix].tran && ix < 32; ix++) {
ntx[ix].tran = tn;
ntx[ix].proc = u.u_procp->p_pid;
ntx[ix].dev = x->dev;
}
n = istwrite(cip, (char *)x, sizeof(*x));
netabuf.s = 3;
if(n == -1) {
y->errno = EIO;
goto bad;
}
netabuf.s = 4;
if(x->count > 0 && x->buf && x->cmd != NREAD) {
n = istwrite(cip, x->buf, x->count);
if(n == -1)
goto bad;
}
readagain:
netabuf.s = 5;
n = istread(cip, (char *)y, sizeof(*y), 0);
netabuf.s = 6;
if(n != sizeof(*y))
goto bad;
if(y->errno == 0 && x->cmd == NREAD) {
n = istread(cip, x->buf, y->count, 0);
if(n != y->count) {
printf("read %d expected %d\n", n, y->count);
/* shut it down */
istwrite(cip, (char *)x, 0);
goto bad;
}
}
if(y->errno == 0) {
if(y->trannum != tn) {
if(y->trannum < tn) /* distant past */
goto readagain;
printf("sent %d got %d\n", tn, y->trannum);
goto bad;
}
addx(x);
addy(y);
if(ix < 32)
ntx[ix].tran = 0;
cip->i_un.i_key = 0;
wakeup((caddr_t)cip);
return;
}
bad:
cip->i_un.i_key = 0;
if(ix < 32)
ntx[ix].tran = 0;
for(ix = 0; ix < 32; ix++)
if(ntx[ix].tran)
printf("tran %d proc %d 0x%x\n", ntx[ix].tran, ntx[ix].proc, ntx[ix].dev);
wakeup((caddr_t)cip);
addx(x);
addy(y);
if(y->errno)
return;
y->errno = EIO;
}
static struct D { struct D *a; char *b;} VER = {&VER,"\n85/6/9:neta.c\n"};