V8/usr/sys/sys/neta.c

Compare this file to the similar file:
Show the results in this format:

#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"};