V9/sys/sys/proca.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/psl.h"*/
#include "../h/stat.h"
#include "../h/buf.h"
#include "../h/mount.h"
#include "../machine/pte.h"
#include "../h/cmap.h"
/*#include "../h/mtpr.h"*/
#include "../h/vmparam.h"
#include "../h/vmmac.h"
#include "../h/proc.h"
#include "../h/text.h"
#include "../h/file.h"
/*#include "../h/reg.h"*/
#include "../h/pioctl.h"
#include "../machine/psl.h"

/* I/O via /proc returns EBUSY if any of these bits are set in p_flag: */

#define	SPRBUSY	(SLOCK|SPAGE|SKEEP|SWEXIT|SVFORK|SVFDONE|SNOVM|SPROCIO)

#ifdef vax
#define SYSADR	((caddr_t)0x80000000)	/* virtual address  of system seg. */
#define SYSP	btop(0x80000000)	/* virtual page no. of system seg. */
#endif
#ifdef sun
#define SYSADR	((caddr_t)USRSTACK)	/* virtual address  of system seg. */
#define SYSP	btop(USRSTACK)		/* virtual page no. of system seg. */
#endif

#define TEXT		0
#define DATA		1
#define STACK		2
#define USERAREA	3

#define min(a,b)	((a) <= (b) ? (a) : (b))

/* inumber to pid */
#define PRMAGIC 64

#define PROCDEV (dev_t)0

struct proc *prpidlock, *prpidwant, *pfind();

extern struct pte Prbufmap[]; extern char priobuf[];
struct pte *prclmap();

prput(ip)
struct inode *ip;
{	struct proc *p;
	if(ip->i_number == ROOTINO)
		return;
	p = pfind(ip->i_number - PRMAGIC);
	if(p == 0) {
		/* printf("prput(%d)?\n", ip->i_number - PRMAGIC); */
		return;
	}
	p->p_trace = 0;
}

struct inode *
prget(fip, dev, ino, ip)
register struct inode *fip;
register struct inode *ip;
{
	register struct proc *p;
	if(ino == ROOTINO) {	/* fake up an inode */
		ip->i_mode = IFDIR | 0555;	/* dir, read and search */
		ip->i_nlink = 2;		/* complete fake */
		ip->i_uid = ip->i_gid = 0;
		ip->i_size = (nproc + 2) * sizeof(struct direct);
		return(ip);
	}
	p = pfind(ino - PRMAGIC);
	if (p == 0 || p->p_trace) {
		iput(ip);
		u.u_error = ENOENT;
		return(0);
	}
	p->p_trace = ip;
	if (p->p_textp && p->p_textp->x_iptr && access(p->p_textp->x_iptr, IREAD))
		ip->i_mode = IFREG;		/* regular, no permissions */
	else
		ip->i_mode = IFREG | 0600;	/* regular, r/w only by owner */
	ip->i_nlink = 1;
	ip->i_uid = p->p_uid;
	ip->i_gid = 1;			/* who cares */
	ip->i_size = (int)ptob(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES);
	ip->i_un.i_proc = p;		/* the sanity check */
	ip->i_un.i_sigmask = 0;		/* signal trace mask */
	return(ip);
}

prfree(ip)
struct inode *ip;
{}

prupdat(ip, ta, tm, waitfor)
struct inode *ip;
time_t *ta, *tm;
{}

#define SDSIZ	sizeof(struct direct)

prread(ip)
struct inode *ip;
{
	static struct direct dotbuf[] = {
		{ ROOTINO, "."},
		{ ROOTINO, ".."}
	};
	struct direct dirbuf;
	register int i, n, j;
	int minproc, maxproc, modoff;
	struct proc *p;

	if (ip->i_number == ROOTINO) {	/* fake up . .. and the proc inodes */
		if (u.u_offset < 0 || u.u_offset >= ip->i_size ||
		    u.u_count <= 0)
			return;
		if (u.u_offset < 2*SDSIZ) {
			iomove((caddr_t)dotbuf + u.u_offset,
			    min(u.u_count, 2*SDSIZ - u.u_offset), B_READ);
			if (u.u_count <= 0 || u.u_error)
				return;
		}
		minproc = (u.u_offset - 2*SDSIZ)/SDSIZ;
		maxproc = (u.u_offset + u.u_count - 1)/SDSIZ;
		modoff = u.u_offset % SDSIZ;
		for (j = 0; j < DIRSIZ; j++)
			dirbuf.d_name[j] = 0;
		for (i=minproc; i<min(maxproc,nproc); i++) {
			if (n = proc[i].p_pid) {
				dirbuf.d_ino = n + PRMAGIC;
				for (j = 4; j >= 0; j--)
					dirbuf.d_name[j] = n%10 + '0', n /= 10;
			} else {
				dirbuf.d_ino = 0;
			}
			iomove((caddr_t)&dirbuf + modoff,
			    min(u.u_count, SDSIZ - modoff), B_READ);
			if (u.u_count <= 0 || u.u_error)
				return;
			modoff = 0;
		}
	} else if (p = pfind(ip->i_number - PRMAGIC)) {
		if (prlock(p))
			return;
		prusrio(p, B_READ);
		prunlock(p);
	} else {
		u.u_error = ENOENT;
	}
}

prwrite(ip)
struct inode *ip;
{
	register struct proc *p;
	if (ip->i_number == ROOTINO) {
		u.u_error = EISDIR;
	} else if (p = pfind(ip->i_number - PRMAGIC)) {
		if (prlock(p))
			return;
		prusrio(p, B_WRITE);
		prunlock(p);
	} else {
		u.u_error = ENOENT;
		return;
	}
}

prtrunc(ip)
struct inode *ip;
{}

prstat(ip, ub)
struct inode *ip;
struct stat *ub;
{	struct stat ds; struct proc *p = (struct proc *)0;
	if(ip->i_number == ROOTINO || (p=pfind(ip->i_number - PRMAGIC))) {
		ds.st_dev = -1;		/* who knows */
		ds.st_ino = ip->i_number;
		ds.st_mode = ip->i_mode;
		ds.st_nlink = ip->i_nlink;
		ds.st_uid = ip->i_uid;
		ds.st_gid = ip->i_gid;
		ds.st_rdev = -1;
		if (p) ip->i_size =
			(int)ptob(p->p_tsize+p->p_dsize+p->p_ssize+UPAGES);
		ds.st_size = ip->i_size;
		ds.st_atime = ds.st_mtime = ds.st_ctime = time;
		if(copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
			u.u_error = EFAULT;
	}
	else
		u.u_error = ENOENT;
}

prnami(p, pflagp, follow)
register struct nx *p;
struct argnamei **pflagp;
{
	register char *cp = p->cp;
	register struct inode *dp = p->dp;
	register int n = 0;

	if ((dp->i_mode & IFMT) != IFDIR)
		u.u_error = ENOTDIR;
	(void) access(dp, IEXEC);
	if (*pflagp)
		u.u_error = EPERM;
	if (u.u_error)
		return 1;
	if (cp[0] == '.') {
		if (cp[1] == 0)
			return 0;
		if (cp[1] == '/')
			return (p->cp = cp + 2), 2;
		if (cp[1] != '.' || (cp[2] && cp[2] != '/'))
			return (u.u_error = ENOENT), 1;
		p->dp = dp->i_mpoint;
		iput(dp);
		plock(p->dp);
		p->dp->i_count++;
		return 2;
	}
	while (*cp) {
		if(*cp < '0' || *cp > '9')
			return (u.u_error = ENOENT), 1;
		n = 10 * n + *cp++ - '0';
	}
	prele(dp);
	p->dp = iget(dp, PROCDEV, n + PRMAGIC);
	iput(dp);
	return 0;
}

prmount(sip, ip, flag, mnt, fstyp)
struct inode *sip, *ip;
{
	if (!suser())
		return;
	if (mnt)
		pron(sip, ip, flag, fstyp);
	else
		proff(ip, fstyp);
}

pron(sip, ip, flag, fstyp)
struct inode *sip;
register struct inode *ip;
{
	register struct inode *rip;
	struct inode pi;

	if (ip->i_fstyp == fstyp) {
		u.u_error = EBUSY;
		return;
	}
	pi.i_fstyp = fstyp;
	pi.i_mpoint = NULL;
	if ((rip = iget(&pi, PROCDEV, (ino_t)ROOTINO)) == NULL) {
		u.u_error = EINVAL;
		return;
	}
	if (rip->i_mpoint) {
		iput(rip);
		u.u_error = EBUSY;
		return;
	}
	prele(rip);
	rip->i_mpoint = ip;
	ip->i_mroot = rip;
	ip->i_flag |= IMOUNT;
	ip->i_count++;
}

proff(mip, fstyp)
struct inode *mip;
{
	struct inode *rip;

	plock(mip);
	rip = mip->i_mroot;
	mip->i_flag &=~ IMOUNT;
	mip->i_mpoint = NULL;
	iput(mip);
	plock(rip);
	iput(rip);
}

/* special tracing stuff */
prioctl(ip, cmd, cmaddr)
struct inode *ip;
caddr_t cmaddr;
{	register struct proc *p; struct text *xp; struct inode *ixp;
	unsigned int signo; int n;
	switch (cmd) {
	default:
		u.u_error = EINVAL;
		return;

	case PIOCGETPR:		/* read struct proc */
	case PIOCOPENT:		/* open text file for reading */
	case PIOCSTOP:		/* send STOP signal and... */
	case PIOCWSTOP:		/* wait for process to STOP */
	case PIOCRUN:		/* make process runnable */
	case PIOCSMASK:		/* set signal trace mask */
	case PIOCCSIG:		/* clear current signal */
	case PIOCSSIG:		/* set current signal */
	case PIOCKILL:		/* send signal */
	case PIOCSEXEC:		/* stop on exec */
	case PIOCREXEC:		/* run on exec */
	case PIOCNICE:		/* set nice priority */
		p = pfind(ip->i_number - PRMAGIC);
		if (p == 0) {
			u.u_error = ENOENT;
			return;
		}
	}
	switch (cmd) {
	case PIOCGETPR:		/* read struct proc */
		u.u_base = cmaddr;
		u.u_offset = 0;
		u.u_count = sizeof(struct proc);
		iomove((char *)p, sizeof(struct proc), B_READ);
		return;

	case PIOCOPENT:		/* open text file for reading */
		if ((xp = p->p_textp) && (ixp = xp->x_iptr)) {
			plock(ixp);
			ixp->i_count++;
			open1(ixp, FREAD, 0);
		} else
			u.u_error = ENOENT;
		return;

	case PIOCSTOP:		/* send STOP signal and... */
		if (p->p_stat != SSTOP) {
			psignal(p, SIGSTOP);
		}
				/* fall through */
	case PIOCWSTOP:		/* wait for process to STOP */
		if (p->p_stat != SSTOP)
			tsleep((caddr_t)p->p_trace, PZERO+1, 0);
		if (p->p_pid != (ip->i_number - PRMAGIC)
		||  p->p_stat == SZOMB)
			u.u_error = ENOENT;
		else if (p->p_stat != SSTOP)
			u.u_error = EINTR;
		return;

	case PIOCRUN:		/* make process runnable */
		if (p->p_stat == SSTOP) {
			setrun(p);
		}
		return;

	case PIOCSMASK:		/* set signal trace mask */
		if (useracc((caddr_t)cmaddr, 4, B_READ)) {
			if (p->p_trace->i_un.i_sigmask = fuword((caddr_t)cmaddr))
				p->p_flag |=  (STRC|SPROCTR);
			else
				p->p_flag &= ~(STRC|SPROCTR);
		} else
			u.u_error = EFAULT;
		return;

	case PIOCCSIG:		/* clear current signal */
		p->p_cursig = 0;
		return;

	case PIOCSSIG:		/* set current signal */
		if (p->p_stat != SSTOP)
			u.u_error = EBUSY;
		else if (useracc((caddr_t)cmaddr, 4, B_READ)) {
			if ((signo = (u_long)fuword((caddr_t)cmaddr)) > NSIG)
				u.u_error = EINVAL;
			else
				p->p_cursig = signo;
		} else
			u.u_error = EFAULT;
		return;

	case PIOCKILL:		/* send signal */
		if (useracc((caddr_t)cmaddr, 4, B_READ)) {
			if ((signo = (u_long)fuword((caddr_t)cmaddr)) > NSIG)
				u.u_error = EINVAL;
			else
				psignal(p, signo);
		} else
			u.u_error = EFAULT;
		return;

	case PIOCSEXEC:		/* stop on exec */
		p->p_flag |=  SSEXEC;
		return;

	case PIOCREXEC:		/* run on exec */
		p->p_flag &= ~SSEXEC;
		return;

	case PIOCNICE:		/* set nice priority */
		if (useracc((caddr_t)cmaddr, 4, B_READ)) {
			n = p->p_nice + fuword((caddr_t)cmaddr);
			if (n >= 2*NZERO)
				n = 2*NZERO -1;
			if (n < 0)
				n = 0;
			if (n < p->p_nice && !suser())
				return;
			p->p_nice = n;
			(void) setpri(p);
		} else
			u.u_error = EFAULT;
		return;

	default:
		panic("prioctl");
	}
}

/* Lock the process p. */

prlock(p)
register struct proc *p;
{
	int s;

	if (p != u.u_procp) {
	waitloop:
		if (prpidlock == p) {		/* wait if p has the interlock */
			prpidwant = u.u_procp;
			if (tsleep((caddr_t)&prpidlock, PZERO+1, 0) == TS_SIG)
				return (u.u_error = EINTR);
			goto waitloop;
		}
		if (p->p_flag & SPAGE) {	/* wait if p is paging */
			p->p_flag |= SPROCWT;
			if (tsleep((caddr_t)&(p->p_stat), PZERO+1, 0) == TS_SIG)
				return (u.u_error = EINTR);
			goto waitloop;
		}

		s = spl6();	/* keep clock out */

		if (p->p_flag&SPRBUSY || (p->p_stat != SSLEEP &&
		    p->p_stat != SRUN && p->p_stat != SSTOP)) {
			splx(s);
			return (u.u_error = EBUSY);
		}
		if (p->p_flag&SLOAD && p->p_stat == SRUN)
			remrq(p);	/* he's now invisible to swtch() */

		/* interlock; also causes swapin, inhibits swapout, setrq, remrq */

		p->p_flag |= SPROCIO;

		splx(s);	/* now do your worst, we don't care */
	}
	u.u_procp->p_flag |= SKEEP;	/* if we get swapped, could deadlock */

	while ((p->p_flag&SLOAD) == 0) {
		/* sched will see SPROCIO, swap him in, and signal us */
		if (tsleep((caddr_t)&p->p_addr, PZERO+1, 0) == TS_SIG) {
			prunlock(p);
			return (u.u_error = EINTR);
		}
	}
	while (prpidlock) {
		prpidwant = u.u_procp;
		if (tsleep((caddr_t)&prpidlock, PZERO+1, 0) == TS_SIG) {
			prunlock(p);
			return (u.u_error = EINTR);
		}
	}
	prpidlock = u.u_procp;
	/* now map his user area into kernel space */
	uaccess(p, Prusrmap, &prusrutl);

	return (u.u_error = 0);
}

/* Undo prlock. */

prunlock(p)
register struct proc *p;
{
	int s;

	u.u_procp->p_flag &= ~SKEEP;

	if (p != u.u_procp) {
		s = spl6();	/* keep clock out during process state change */
		p->p_flag  &= ~SPROCIO;
		if (p->p_flag&SLOAD && p->p_stat == SRUN)
			setrq(p);	/* visible again to swtch() */
		splx(s);
	}
	if (prpidlock == u.u_procp) {
		prpidlock = 0;
		if (prpidwant) {
			prpidwant = 0;
			wakeup((caddr_t)&prpidlock);
		}
	}
	return 0;
}

/* Read/write from/to process p. */

#define REGADR(i)	((caddr_t)(regbase + i))
#define SEEKADR		((caddr_t)u.u_offset)

prusrio(p, flag)
register struct proc *p; int flag;
{
	register int *regbase;
	caddr_t maxadr; int segment, resid;
	register int v;

	u.u_error = 0;
	if ((u_long)SEEKADR < (u_long)(SYSADR)) {
		v = btop(SEEKADR);
		if (v < LOWPAGES)
			u.u_error = EIO;
		else if (isassv(p,v)) {
			segment = STACK;
			maxadr = (caddr_t)USRSTACK;
		}
		else if (isatsv(p,v)) {
			segment = TEXT;
			maxadr = ptob(tptov(p, p->p_tsize));
		}
		else if (isadsv(p,v)) {
			segment = DATA;
			maxadr = ptob(dptov(p, p->p_dsize));
		}
		else
			u.u_error = EIO;
	}
	else if (SEEKADR >= (caddr_t)&u &&
		 SEEKADR < (maxadr = (caddr_t)&u + sizeof(u)))
		segment = USERAREA;
	else
		u.u_error = EIO;

	if (u.u_error) return;

	if ((flag & B_READ) == 0) switch(segment) {
	case TEXT:
		prxdup(p);
		break;
	case USERAREA:
		regbase = prusrutl.u_ar0;
		if (SEEKADR < REGADR(R0) ||
		    (u_long)SEEKADR >= (u_long)(maxadr = REGADR(PC+1)))
			u.u_error = EIO;
		regbase = (int *)((u_long)&prusrutl + (u_long)regbase - (u_long)&u);
		if ((regbase[PS]&PSL_USERSET) != PSL_USERSET ||
		    (regbase[PS]&PSL_USERCLR) != 0)
			u.u_error = EBUSY;
		break;
	}

	if (u.u_error) return;

	resid = u.u_count;
	if ((u_long)((u_long)u.u_offset + (u_long)u.u_count) >= (u_long)maxadr)
		u.u_count = maxadr - (caddr_t)u.u_offset;
	resid -= u.u_count;

	if (segment == USERAREA) {
		iomove((caddr_t)&prusrutl + ((u_long)u.u_offset - (u_long)&u),
			u.u_count, flag);
		if ((flag & B_READ) == 0) {
			regbase[PS] |=  PSL_USERSET;
			regbase[PS] &= ~PSL_USERCLR;
		}
	} else
		priomove(p, flag);

	u.u_count += resid;
}

/* Move data between the object process and us. */

priomove(p, flag)
	register struct proc *p;
{
	register struct pte *pte;
	register clofset, clcount;
	int waslocked;

	while (u.u_count > 0 && u.u_error == 0) {
		pte = prclmap(p, (caddr_t)u.u_offset, &waslocked);
		clofset = u.u_offset & CLOFSET;
		clcount = min(u.u_count, CLSIZE*NBPG - clofset);
		iomove(&priobuf[clofset], clcount, flag);
		prclunmap(p, pte, flag | waslocked);
	}
}

/* Map and lock a cluster from process into system space. */

struct pte *
prclmap(p, vaddr, flagp)
	register struct proc *p;
	register caddr_t vaddr;
	int *flagp;
{
	register i;
	register struct pte *pte;
	i = clbase(btop(vaddr));
	pte = vtopte(p, i);

	*flagp = 0;
	if (pte->pg_v) {
		if (cmap[pgtocm(pte->pg_pfnum)].c_lock)
			*flagp = B_PHYS;
		else
			mlock(pte->pg_pfnum);
	} else {
#ifdef vax
		p->p_flag |= SDLYU;
		pagein(vaddr, &prusrutl);
		p->p_flag &= ~SDLYU;
#endif
#if sun
		pagein(vaddr, &prusrutl, 1);
#endif
		if (!pte->pg_v)
			panic("prclmap: pte not valid after pagein");
	}
#ifdef vax
	for (i=0; i<CLSIZE; i++) {
		*(int *)(Prbufmap + i) = PG_V | PG_KW | (pte->pg_pfnum + i);
		mtpr(TBIS, &priobuf[i*NBPG]);
	}
#endif
#ifdef sun
	mapin(Prbufmap, btop(priobuf), pte->pg_pfnum,CLSIZE,(int)(PG_V|PG_KW));
#endif
	return pte;
}

/* Release a cluster, updating its pte's. */

prclunmap(p, pte, flag)
	struct proc *p;
	register struct pte *pte;
{
	register i;
	if ((flag & B_PHYS) == 0)
		munlock(pte->pg_pfnum);
	if ((flag & B_READ) == 0) { /* Write to device writes memory */
		for (i=0; i<CLSIZE; i++)
			(pte+i)->pg_m = 1;
#if sun
		p->p_flag |= SPTECHG;
#endif
	}
}

/* Prepare the process' text segment for writing, duplicating it if necessary. */

prxdup(p)
	register struct proc *p;
{
	register struct text *xp, *pxp;

	if ((pxp = p->p_textp) == 0)
		return 0;
	if (!(pxp->x_flag&XPAGI) && pxp->x_count == 1) {
		pxp->x_flag |= XTRC|XWRIT;
		return 0;
	}
	if (pxp->x_flag&XTRC)
		panic("prxdup");

	for (xp = text; xp < textNTEXT && xp->x_iptr; xp++)
		/* void */ ;
	if (xp >= textNTEXT)
		return (u.u_error = ENOSPC);

	xp->x_flag = XLOCK|XTRC|XLOAD;
	xp->x_size = pxp->x_size;
	if (vsxalloc(xp) == NULL)
		return (u.u_error = ENOSPC);

	xp->x_count = 1;
	xp->x_ccount = 0;
	xp->x_rssize = 0;
	(xp->x_iptr = pxp->x_iptr)->i_count++;

	xlock(pxp);
	--pxp->x_count;
	pxp->x_flag &= ~XLOCK;
	xccdec(pxp, p);

	p->p_textp = xp;
	xlink(p);
	p->p_flag &= ~SPAGI;

	prxread(p, &prusrutl);

	xp->x_flag |= XWRIT;
	xp->x_flag &= ~XLOAD;
	xunlock(xp);
	return u.u_error;
}

prxread(p, up)
	register struct proc *p;
	struct user *up;
{
	register struct inode *ip = p->p_textp->x_iptr;
	register count; register struct pte *pte;
	register caddr_t vaddr; int waslocked;
	caddr_t gettmem();

	caddr_t ubase = u.u_base; unsigned int ucount = u.u_count;
	off_t uoffset = u.u_offset;
	vaddr = gettmem(up);

	plock(ip);
	ip->i_flag |= ITEXT;

	count = up->u_exdata.ux_tsize;
	u.u_offset = gettfile(up);

	u.u_segflg = 1;
	u.u_count = 0;
	while (count > 0 && u.u_count == 0) {
		pte = prclmap(p, vaddr, &waslocked);
		u.u_base = (caddr_t)priobuf;
		count -= u.u_count = min(count, CLSIZE*NBPG);
		vaddr += u.u_count;
		readi(ip);
		prclunmap(p, pte, B_WRITE | waslocked);
	}
	prele(ip);

	u.u_base = ubase; u.u_count = ucount;
	u.u_offset = uoffset; u.u_segflg = 0;

	return (count ? (u.u_error = EIO) : 0);
}