h through the
 * I list is instituted to pick up 100 more.
 */
ialloc(dev)
{
	register *fp, *bp, *ip;
	int i, j, k, ino;

	fp = getfs(dev);
	while(fp->s_ilock)
		sleep(&fp->s_ilock, PINOD);
loop:
	if(fp->s_ninode > 0) {
		ino = fp->s_inode[--fp->s_ninode];
		ip = iget(dev, ino);
		if (ip==NULL)
			return(NULL);
		if(ip->i_mode == 0) {
			for(bp = &ip->i_mode; bp < &ip->i_addr[8];)
				*bp++ = 0;
			if(fp->s_tinode) fp->s_tinode--;
			fp->s_fmod = 1;
			return(ip);
		}
		/*
		 * Inode was allocated after all.
		 * Look some more.
		 */
		iput(ip);
		goto loop;
	}
	fp->s_ilock++;
	ino = 0;
	for(i=0; i<fp->s_isize; i++) {
		bp = bread(dev, i+2);
		ip = bp->b_addr;
		for(j=0; j<256; j=+16) {
			ino++;
			if(ip[j] != 0)
				continue;
			for(k=0; k<v.v_inode; k++)
			if(dev==inode[k].i_dev && ino==inode[k].i_number)
				goto cont;
			fp->s_inode[fp->s_ninode++] = ino;
			if(fp->s_ninode >= 100)
				break;
		cont:;
		}
		brelse(bp);
		if(fp->s_ninode >= 100)
			break;
	}
	fp->s_ilock = 0;
	wakeup(&fp->s_ilock);
	if (fp->s_ninode > 0)
		goto loop;
	prdev("Out of inodes", dev);
	u.u_error = ENOSPC;
	fp->s_tinode = 0;
	return(NULL);
}

/*
 * Free the specified I node on the specified device.
 * The algorithm stores up to 100 I nodes in the super
 * block and throws away any more.
 */
ifree(dev, ino)
{
	register *fp;

	fp = getfs(dev);
	fp->s_tinode++;
	if(fp->s_ilock)
		return;
	if(fp->s_ninode >= 100)
		return;
	fp->s_inode[fp->s_ninode++] = ino;
	fp->s_fmod = 1;
}

/*
 * getfs maps a device number into a pointer to the incore super block.
 * The algorithm is a linear search through the mount table.
 * A consistency check of the in core free-block and i-node counts.
 *
 * bad count on dev x/y -- the count
 *	check failed. At this point, all
 *	the counts are zeroed which will
 *	almost certainly lead to "no space"
 *	diagnostic
 * panic: no fs -- the device is not mounted.
 *	this "cannot happen"
 */
getfs(dev)
{
	register struct mount *p;
	register char *n1, *n2;

	for (p = &mount[0]; p < v.ve_mount; p++)
	if(p->m_bufp != NULL && p->m_dev == dev) {
		p = p->m_bufp->b_addr;
		n1 = p->s_nfree;
		n2 = p->s_ninode;
		if(n1 > 100 || n2 > 100) {
			prdev("bad count", dev);
			p->s_nfree = 0;
			p->s_ninode = 0;
		}
		return(p);
	}
	panic("no fs");
}

/*
 * update is the internal name of 'sync'. It goes through the disk
 * queues to initiate sandbagged IO; goes through the I nodes to write
 * modified nodes; and it goes through the mount table to initiate modified
 * super blocks.
 */
update()
{
	register struct inode *ip;
	register struct mount *mp;
	register *bp;

	if(updlock)
		return;
	updlock++;
	for (mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp != NULL) {
			ip = mp->m_bufp->b_addr;
			if(ip->s_fmod==0 || ip->s_ilock!=0 ||
			   ip->s_flock!=0 || ip->s_ronly!=0)
				continue;
			bp = getblk(mp->m_dev, 1);
			ip->s_fmod = 0;
			ip->s_time = time;
			bcopy(ip, bp->b_addr, 256);
			bwrite(bp);
		}
	for (ip = &inode[0]; ip < v.ve_inode; ip++)
		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
			ip->i_flag =| ILOCK;
			ip->i_count++;
			iupdat(ip);
			iput(ip);
		}
	updlock = 0;
	bflush(NODEV);
}
	for (mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp != NULL) {
			ip = mp->m_bufp->b_addr;
			if(ip->s_fmod==0 || ip->s_ilock!=0 ||
			   ip->s_flock!=0 || ip->s_ronly!=0)
				continue;
			bp = getblk(mp->m_dev, 1);
			ip->s_fmod = 0;
			ip->s_time = time;
			bcopy(ip, bp->b_addr, 256);
			bwrite(bp);
		}
	for (ip = &inode[0]; ip < v.ve_inode; ip++)
		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
			ip->i_flag =| ILOCK;
			ip->i_#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/var.h"

int	sstime;
int	rrcput[256];

#define	UMODE	0170000
#define	SCHMAG	8/10

/*
 * clock is called straight from
 * the real time clock interrupt.
 *
 * Functions:
 *	reprime clock
 *	copy *switches to display
 *	implement callouts
 *	maintain user/system times
 *	maintain date
 *	profile
 *	tout wakeup (sys sleep)
 *	lightning bolt wakeup (every 4 sec)
 *	alarm clock signals
 *	jab the scheduler
 */
clock(dev, sp, r1, nps, r0, pc, ps)
{
	register struct callo *p1, *p2;
	register struct proc *pp;
	int a;

	/*
	 * restart clock
	 */

	*lks = 0115;

	/*
	 * display register
	 */

	display();

	/*
	 * callouts
	 * if none, just return
	 * else update first non-zero time
	 */

	if(callout[0].c_func == 0)
		goto out;
	p2 = &callout[0];
	while(p2->c_time<=0 && p2->c_func!=0)
		p2++;
	p2->c_time--;

	/*
	 * if ps is high, just return
	 */

	if((ps&0340) != 0)
		goto out;

	/*
	 * callout
	 */

	spl5();
	if(callout[0].c_time <= 0) {
		p1 = &callout[0];
		while(p1->c_func != 0 && p1->c_time <= 0) {
			(*p1->c_func)(p1->c_arg);
			p1++;
		}
		p2 = &callout[0];
		while(p2->c_func = p1->c_func) {
			p2->c_time = p1->c_time;
			p2->c_arg = p1->c_arg;
			p1++;
			p2++;
		}
	}

	/*
	 * lightning bolt time-out
	 * and time of day
	 */

out:
	sstime++;
	rrcput[u.u_ruid&0377]++;
	if((ps&UMODE) == UMODE) {
		u.u_utime++;
		if(u.u_prof[3])
			incupc(pc, u.u_prof);
	} else
		u.u_stime++;
	pp = u.u_procp;
	if(++pp->p_cpu == 0)
		pp->p_cpu--;
	if(++lbolt >= HZ) {
		if((ps&0340) != 0)
			return;
		lbolt =- HZ;
		++time;
		spl1();
		if (time == tout)
			wakeup(&tout);
		runrun++;
		if((time.loword&01) == 0)
			wakeup(&lbolt);
		for(pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_stat) {
			if(pp->p_time != 127)
				pp->p_time++;
			if(pp->p_clktim)
				if(--pp->p_clktim == 0)
					psignal(pp, SIGCLK);
			pp->p_cpu =>> 1;
			if(pp->p_pri >= PUSER)
				setpri(pp);
		}
		if(runin!=0) {
			runin = 0;
			setrun(&proc[0]);
		}
		if((ps&UMODE) == UMODE) {
			u.u_ar0 = &r0;
			if(issig())
				psig();
			setpri(u.u_procp);
		}
	}
}

/*
 * timeout is called to arrange that fun(arg) is called in tim/HZ seconds.
 * An entry is sorted into the callout structure.
 * The time in each structure entry is the number of HZ's more
 * than the previous entry. In this way, decrementing the
 * first entry has the effect of updating all entries.
 *
 * The panic is there because there is nothing
 * intelligent to be done if an entry won't fit.
 */
timeout(fun, arg, tim)
{
	register struct callo *p1, *p2;
	register t;
	int s;

	t = tim;
	s = PS->integ;
	p1 = &callout[0];
	spl7();
	while(p1->c_func != 0 && p1->c_time <= t) {
		t =- p1->c_time;
		p1++;
	}
	if (p1 >= &callout[v.v_call-1])
		panic("Timeout table overflow");
	p1->c_time =- t;
	p2 = p1;
	while(p2->c_func != 0)
		p2++;
	while(p2 >= p1) {
		(p2+1)->c_time = p2->c_time;
		(p2+1)->c_func = p2->c_func;
		(p2+1)->c_arg = p2->c_arg;
		p2--;
	}
	p1->c_time = t;
	p1->c_func = fun;
	p1->c_arg = arg;
	PS->integ = s;
}
tim)
{
	register struct callo *p1, *p2;
	register t;
	int s;

	t = tim;
	s = PS->integ;
	p1 = &callout[0];
	spl7();
	while(p1->c_func != 0 && p1->c_time <= t) {
		t =- p1->c_time;
		p1++;
	}
	if (p1 >= &callout[v.v_call-1])
		panic("Timeout table overflow");
	p1->c_time =- t;
	p2 = p1;
	while(p2->c_func != 0)
		p2++;
	while(p2 >= p1) {
		(p2+1)->c_time = p2->c_time;
		(p2+1)->c_func = p2->c_func;
		(p2+1)->c_arg = p2->c_arg;
		p2--;
	}
	p1->c_time = t;
	p1->c_func = fun;
	p1->c_arg = ar#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/filsys.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/systm.h"
#include "../hd/var.h"

/*
 * Convert a user supplied file descriptor into a pointer
 * to a file structure.
 * Only task is to check range of the descriptor.
 */
getf(f)
{
	register *fp, rf;

	rf = f;
	if (0<=rf && rf<NOFILE) {
		fp = u.u_ofile[rf];
		if(fp != NULL)
			return(fp);
	}
	u.u_error = EBADF;
	return(NULL);
}

/*
 * Internal form of close.
 * Decrement reference count on file structure.
 * Also make sure the pipe protocol does not constipate.
 *
 * Decrement reference count on the inode following
 * removal to the referencing file structure.
 * On the last close switch out the the device handler for
 * special files.  Note that the handler is called
 * on every open but only the last close.
 */
closef(fp)
int *fp;
{
	register *ip;
	register struct file *rfp;
	int flag;
	register int (*cfunc)();

	if ((rfp = fp) == NULL)
		return;
	ip = rfp->f_inode;
	if (rfp->f_count > 1) {
		rfp->f_count--;
		return;
	}
	plock(ip);
	flag = rfp->f_flag&FWRITE;
	rfp->f_count = 0;
	if(rfp->f_flag&FPIPE) {
		ip->i_mode =& ~(IREAD|IWRITE);
		wakeup(ip+1);
		wakeup(ip+2);
	}
	cfunc = 0;
	if ((ip->i_mode&IFMT) == IFCHR)
		cfunc = cdevsw[major(ip->i_addr[0])].d_close;
	else if ((ip->i_mode&IFMT)== IFBLK)
		cfunc = bdevsw[major(ip->i_addr[0])].d_close;
	iput(ip);
	if (cfunc == 0)
		return;
	for (rfp=file; rfp < v.ve_file; rfp++)
		if (rfp->f_count && rfp->f_inode==ip)
			return;
	(*cfunc)(minor(ip->i_addr[0]), flag);
}

/*
 * openi called to allow handler of special files to initialize and
 * validate before actual IO.
 * Called only for open of special files.
 */
openi(ip, rw)
register *ip;
{
	register dev, maj;

	dev = minor(ip->i_addr[0]);
	maj = major(ip->i_addr[0]);
	if ((ip->i_mode&IFMT) == IFCHR)
		if (maj >= cdevcnt)
			u.u_error = ENXIO; else
		{
			if (u.u_ttyp == 0)
				u.u_ttyd = ip->i_addr[0];
			(*cdevsw[maj].d_open)(dev, rw);
		} else
		if (maj >= bdevcnt)
			u.u_error = ENXIO; else
			(*bdevsw[maj].d_open)(dev, rw);
}

/*
 * Check mode permission on inode pointer.
 * Mode is READ, WRITE or EXEC.
 * In the case of WRITE, the read-only status of the file
 * system is checked. Also in WRITE, prototype text
 * segments cannot be written.
 * The mode is shifted to select the owner/group/other fields.
 * The super user is granted all permissions.
 */
access(aip, mode)
int *aip;
{
	register *ip, m;

	ip = aip;
	m = mode;
	if(m == IWRITE) {
		if(getfs(ip->i_dev)->s_ronly != 0) {
			u.u_error = EROFS;
			return(1);
		}
		if(ip->i_flag & ITEXT) {
			u.u_error = ETXTBSY;
			return(1);
		}
	}
	if(u.u_uid == 0)
		return(0);
	if(u.u_uid != ip->i_uid) {
		m =>> 3;
		if(u.u_gid != ip->i_gid)
			m =>> 3;
	}
	if((ip->i_mode&m) != 0)
		return(0);

bad:
	u.u_error = EACCES;
	return(1);
}

/*
 * Look up a pathname and test if the resultant inode is owned by the
 * current user. If not, try for super-user.
 * If permission is granted, return inode pointer.
 */
owner()
{
	register struct inode *ip;
	extern uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if(u.u_uid == ip->i_uid)
		return(ip);
	if (suser())
		return(ip);
	iput(ip);
	return(NULL);
}

/*
 * Test if the current user is the super user.
 */
suser()
{

	if(u.u_uid == 0)
		return(1);
	u.u_error = EPERM;
	return(0);
}

/*
 * Allocate a user file descriptor.
 */
ufalloc()
{
	register i;

	for (i=0; i<NOFILE; i++)
		if (u.u_ofile[i] == NULL) {
			u.u_ar0[R0] = i;
			return(i);
		}
	u.u_error = EMFILE;
	return(-1);
}

/*
 * Allocate a user file descriptor and a file structure.
 * Initialize the descriptor to point at the file structure.
 *
 * no file -- if there are no available 	file structures.
 */
falloc()
{
	register struct file *fp;
	register i;

	if ((i = ufalloc()) < 0)
		return(NULL);
	for (fp = &file[0]; fp < v.ve_file; fp++)
		if (fp->f_count==0) {
			u.u_ofile[i] = fp;
			fp->f_count++;
			fp->f_offset[0] = 0;
			fp->f_offset[1] = 0;
			return(fp);
		}
	printf("no file\n");
	u.u_error = ENFILE;
	return(NULL);
}

 * Allocate a user file descriptor and a file structure.
 * Initialize the descriptor to point at the file structure.
 *
 * no file -- if there are no available 	file structures.
 */
falloc()
{
	register struct file *fp;
	register i;

	if ((i = ufalloc()) < 0)
		return(NULL);
	for (fp = &file[0]; fp < v.ve_file; fp++)
		if (fp->f_count==0) {
			u.u_ofile[i] = fp;
			fp->f_count++;
			fp->f_offset[0] = 0;
			fp->f_offset[1] = 0;
			return(fp);
		}
	printf("no f#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/filsys.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Look up an inode by device,inumber.
 * If it is in core (in the inode structure), honor the locking protocol.
 * If it is not in core, read it in from the specified device.
 * If the inode is mounted on, perform the indicated indirection.
 * In all cases, a pointer to a locked inode structure is returned.
 *
 * printf warning: no inodes -- if the inode structure is full
 * panic: no imt -- if the mounted filesystem is not in the mount table.
 *	"cannot happen"
 */
iget(dev, ino)
{
	register struct inode *p;
	register *ip2;
	int *ip1;
	register struct mount *ip;

loop:
	ip = NULL;
	for(p = &inode[0]; p < v.ve_inode; p++) {
		if(dev==p->i_dev && ino==p->i_number) {
			if((p->i_flag&ILOCK) != 0) {
				p->i_flag =| IWANT;
				sleep(p, PINOD);
				goto loop;
			}
			if((p->i_flag&IMOUNT) != 0) {
				for(ip = &mount[0]; ip < v.ve_mount; ip++)
				if(ip->m_inodp == p) {
					dev = ip->m_dev;
					ino = ROOTINO;
					goto loop;
				}
				panic("no imt");
			}
			p->i_count++;
			p->i_flag =| ILOCK;
			return(p);
		}
		if(ip==NULL && p->i_count==0)
			ip = p;
	}
	if((p=ip) == NULL) {
		printf("Inode table overflow\n");
		u.u_error = ENFILE;
		return(NULL);
	}
	p->i_dev = dev;
	p->i_number = ino;
	p->i_flag = ILOCK;
	p->i_count++;
	p->i_lastr = -1;
	ip = bread(dev, ldiv(ino+31,16));
	/*
	 * Check I/O errors
	 */
	if (ip->b_flags&B_ERROR) {
		brelse(ip);
		iput(p);
		return(NULL);
	}
	ip1 = ip->b_addr + 32*lrem(ino+31, 16);
	ip2 = &p->i_mode;
	while(ip2 < &p->i_addr[8])
		*ip2++ = *ip1++;
	brelse(ip);
	return(p);
}

/*
 * Decrement reference count of an inode structure.
 * On the last reference, write the inode out and if necessary,
 * truncate and deallocate the file.
 */
iput(p)
struct inode *p;
{
	register *rp;

	rp = p;
	if(rp->i_count == 1) {
		rp->i_flag =| ILOCK;
		if(rp->i_nlink <= 0) {
			itrunc(rp);
			rp->i_mode = 0;
			rp->i_flag =| IUPD;
			ifree(rp->i_dev, rp->i_number);
		}
		iupdat(rp);
		prele(rp);
		rp->i_flag = 0;
		rp->i_number = 0;
	}
	rp->i_count--;
	prele(rp);
}

/*
 * Check accessed and update flags on an inode structure.
 * If either is on, update the inode with the current time.
 */
iupdat(p)
int *p;
{
	register *ip1, *ip2, *rp;
	int *bp, i;

	rp = p;
	if((rp->i_flag&(IUPD|IACC)) != 0) {
		if(getfs(rp->i_dev)->s_ronly) {
			if(rp->i_flag&IUPD)
				u.u_error = EROFS;
			rp->i_flag =& ~(IUPD|IACC);
			return;
		}
		i = rp->i_number+31;
		bp = bread(rp->i_dev, ldiv(i,16));
		ip1 = bp->b_addr + 32*lrem(i, 16);
		ip2 = &rp->i_mode;
		while(ip2 < &rp->i_addr[8])
			*ip1++ = *ip2++;
		if(rp->i_flag&IACC) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		} else
			ip1 =+ 2;
		if(rp->i_flag&IUPD) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		}
		rp->i_flag =& ~(IUPD|IACC);
		bdwrite(bp);
	}
}

/*
 * Free all the disk blocks associated with the specified inode structure.
 * The blocks of the file are removed in reverse order. This FILO
 * algorithm will tend to maintain
 * a contiguous free list much longer than FIFO.
 */
itrunc(ip)
int *ip;
{
	register *rp, *bp, *cp;
	int *dp, *ep;

	rp = ip;
	if((rp->i_mode&(IFCHR&IFBLK)) != 0)
		return;
	for(ip = &rp->i_addr[7]; ip >= &rp->i_addr[0]; ip--)
	if(*ip) {
		if((rp->i_mode&ILARG) != 0) {
			bp = bread(rp->i_dev, *ip);
			for(cp = bp->b_addr+510; cp >= bp->b_addr; cp--)
			if(*cp) {
				free(rp->i_dev, *cp);
			}
			brelse(bp);
		}
		free(rp->i_dev, *ip);
		*ip = 0;
	}
	rp->i_mode =& ~ILARG;
	rp->i_size0 = 0;
	rp->i_size1 = 0;
	rp->i_flag =| IUPD;
}

/*
 * Make a new file.
 */
maknode(mode)
{
	register *ip;

	ip = ialloc(u.u_pdir->i_dev);
	if (ip==NULL) {
		iput(u.u_pdir);
		return(NULL);
	}
	ip->i_flag =| IACC|IUPD;
	ip->i_mode = mode|IALLOC;
	ip->i_nlink = 1;
	ip->i_uid = u.u_uid;
	ip->i_gid = u.u_gid;
	wdir(ip);
	return(ip);
}

/*
 * Write a directory entry with parameters left as side effects
 * to a call to namei.
 */
wdir(ip)
int *ip;
{
	register char *cp1, *cp2;

	u.u_dent.u_ino = ip->i_number;
	cp1 = &u.u_dent.u_name[0];
	for(cp2 = &u.u_dbuf[0]; cp2 < &u.u_dbuf[DIRSIZ];)
		*cp1++ = *cp2++;
	u.u_count = DIRSIZ+2;
	u.u_segflg = 1;
	u.u_base = &u.u_dent;
	writei(u.u_pdir);
	iput(u.u_pdir);
}
->i_flag =| IACC|IUPD;
	ip->i_mode = mode|IALLOC;
	ip->i_nlink = 1;
	ip->i_uid = u.u_uid;
	ip->i_gid = u.u_gid;
	wdir(ip);
	return(ip);
}

/*
 * Write a directory entry with parameters left as side effects
 * to a call to namei.
 */
wdir(ip)
int *ip;
{
	register char *cp1, *cp2;

	u.u_dent.u#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/inode.h"
#include "../hd/seg.h"

#define	CLOCK1	0177546
#define	CLOCK2	0172540
/*
 * Icode is the octal bootstrap program executed in user mode
 * to bring up the system.
 */
int	icode[]
{
	0104413,	/* sys exec; init; initp */
	0000014,
	0000010,
	0000777,	/* br . */
	0000014,	/* initp: init; 0 */
	0000000,
	0062457,	/* init: </etc/init\0> */
	0061564,
	0064457,
	0064556,
	0000164,
};

/*
 * Initialization code.
 * Called from mch.s as soon as a stack and segmentation
 * have been established.
 * Functions:
 *	clear and free user core
 *	find which clock is configured
 *	hand craft 0th process
 *	call all initialization routines
 *	fork - process 0 to schedule
 *	     - process 1 execute bootstrap
 *
 * panic: no clock -- neither clock responds
 * loop at loc 6 in user mode -- /etc/init
 *	cannot be executed.
 */
main()
{
	register i;

	/*
	 * zero and free all of core
	 */

	printf("\nUnix system %s\n",&pwbname);
	printf("\nRestricted rights:\n");
	printf("Use, duplication or disclosure is subject to restrictions\n");
	printf("stated in your contract with Western Electric Company, Inc.\n");
	i = *ka6 + USIZE;
	UISD->r[0] = 077406;
	for(;;) {
		UISA->r[0] = i;
		if(fuibyte(0) < 0)
			break;
		clearseg(i);
		maxmem++;
		mfree(coremap, 1, i);
		i++;
	}
	printf("\nAvailable user memory = %l * 32 words\n",maxmem);
	maxmem = min(maxmem, MAXMEM);
	mfree(swapmap, nswap, swplo);

	/*
	 * determine clock
	 */

	UISA->r[7] = ka6[1]; /* io segment */
	UISD->r[7] = 077406;
	lks = CLOCK1;
	if(fuiword(lks) == -1) {
		lks = CLOCK2;
		if(fuiword(lks) == -1)
			panic("no clock");
	}

	/*
	 * set up system process
	 */

	proc[0].p_addr = *ka6;
	proc[0].p_size = USIZE;
	proc[0].p_stat = SRUN;
	proc[0].p_flag =| SLOAD|SSYS;
	u.u_procp = &proc[0];

	/*
	 * set up 'known' i-nodes
	 */

	*lks = 0115;
	cinit();
	binit();
	iinit();
	rootdir = iget(rootdev, ROOTINO);
	rootdir->i_flag =& ~ILOCK;
	u.u_cdir = iget(rootdev, ROOTINO);
	u.u_cdir->i_flag =& ~ILOCK;

	/*
	 * make init process
	 * enter scheduling loop
	 * with system process
	 */

	if(newproc()) {
		expand(USIZE+1);
		estabur(0, 1, 0, 0, RO);
		copyout(icode, 0, sizeof icode);
		/*
		 * Return goes to loc. 0 of user init
		 * code just copied out.
		 */
		return;
	}
	sched();
}

/*
 * Load the user hardware segmentation
 * registers from the software prototype.
 * The software registers must have
 * been setup prior by estabur.
 */
sureg()
{
	register *udp, *uap, *rdp;
	int *rap, daddr, taddr, *limudp;

	taddr = daddr = u.u_procp->p_addr;
	if (udp=u.u_procp->p_textp)
		taddr = udp->x_caddr;
	limudp = &u.u_uisd[16];
	if (cputype==40)
		limudp = &u.u_uisd[8];
	rap = UISA;
	rdp = UISD;
	uap = &u.u_uisa[0];
	for (udp = &u.u_uisd[0]; udp < limudp;) {
		*rap++ = *uap++ + (*udp&TX? taddr: daddr);
		*rdp++ = *udp++;
	}
}

/*
 * Set up software prototype segmentation
 * registers to implement the 3 pseudo
 * text,data,stack segment sizes passed
 * as arguments.
 * The argument sep specifies if the
 * text and data+stack segments are to
 * be separated.
 * The last argument determines whether the text
 * segment is read-write or read-only.
 */
estabur(nt, nd, ns, sep, xrw)
{
	register a, *ap, *dp;

	if(checkur(nt, nd, ns, sep))
		return(-1);
	a = 0;
	ap = &u.u_uisa[0];
	dp = &u.u_uisd[0];
	while(nt >= 128) {
		*dp++ = (127<<8) | xrw|TX;
		*ap++ = a;
		a =+ 128;
		nt =- 128;
	}
	if(nt) {
		*dp++ = ((nt-1)<<8) | xrw|TX;
		*ap++ = a;
	}
	if(sep)
	while(ap < &u.u_uisa[8]) {
		*ap++ = 0;
		*dp++ = 0;
	}
	a = USIZE;
	while(nd >= 128) {
		*dp++ = (127<<8) | RW;
		*ap++ = a;
		a =+ 128;
		nd =- 128;
	}
	if(nd) {
		*dp++ = ((nd-1)<<8) | RW;
		*ap++ = a;
		a =+ nd;
	}
	while(ap < &u.u_uisa[8]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	if(sep)
	while(ap < &u.u_uisa[16]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	a =+ ns;
	while(ns >= 128) {
		a =- 128;
		ns =- 128;
		*--dp = (127<<8) | RW;
		*--ap = a;
	}
	if(ns) {
		*--dp = ((128-ns)<<8) | RW | ED;
		*--ap = a-128;
	}
	if(!sep) {
		ap = &u.u_uisa[0];
		dp = &u.u_uisa[8];
		while(ap < &u.u_uisa[8])
			*dp++ = *ap++;
		ap = &u.u_uisd[0];
		dp = &u.u_uisd[8];
		while(ap < &u.u_uisd[8])
			*dp++ = *ap++;
	}
	sureg();
	return(0);

}
checkur(nt, nd, ns, sep)
{
	if(sep) {
		if(cputype == 40)
			goto err;
		if(ctos(nt) > 8 || ctos(nd)+ctos(ns) > 8)
			goto err;
	} else
		if(ctos(nt)+ctos(nd)+ctos(ns) > 8)
			goto err;
	if(nt+nd+ns+USIZE > maxmem)
		goto err;
	return(0);
err:
	u.u_error = ENOMEM;
	return(-1);
}
*--ap = a-128;
	}
	if(!sep) {
		ap = &u.LIB = /sys/sys
DD = tmp
LNAME = lib1

CC = cc
CCFLAGS = -O
HD = /sys/sys/hd

LD = -ld
LDFLAGS = -x

.c.o:
	$(CC) -c $(CCFLAGS) $<
	$(LD) -r $(LDFLAGS) $*.o
	mv a.out $*.o

# install: Create and install /sys/sys/lib1 - os

install:	lib1
	-mv $(LIB)/$(LNAME) $(LIB)/$(DD)$(LNAME)
	mv lib1 $(LIB)/$(LNAME)
	-chown bin $(LIB)/$(LNAME)
	-rm -f $(LIB)/$(DD)$(LNAME)
	ls -l $(LIB)/$(LNAME)

# lib1: Create lib1 in local directory.

lib1:	alloc.o clock.o fio.o iget.o main.o malloc.o nami.o pipe.o \
	prf.o pwbsys.o rdwri.o sig.o slp.o subr.o sys1.o sys2.o \
	sys3.o sys4.o sysent.o text.o trap.o
	-rm -f lib1 tmp.a
	ar r tmp.a main.o alloc.o iget.o prf.o rdwri.o slp.o subr.o text.o trap.o sig.o sysent.o
	ar r tmp.a clock.o fio.o malloc.o nami.o pipe.o sys1.o sys2.o sys3.o sys4.o pwbsys.o
	mv tmp.a lib1

alloc.o:	alloc.c $(HD)/param.h $(HD)/systm.h $(HD)/filsys.h \
	$(HD)/conf.h $(HD)/buf.h $(HD)/inode.h $(HD)/user.h $(HD)/var.h
clock.o:	clock.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/proc.h $(HD)/var.h
fio.o:	fio.c $(HD)/param.h $(HD)/user.h $(HD)/filsys.h $(HD)/file.h \
	$(HD)/conf.h $(HD)/inode.h $(HD)/reg.h $(HD)/systm.h $(HD)/var.h
iget.o:	iget.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/inode.h \
	$(HD)/filsys.h $(HD)/buf.h $(HD)/var.h
main.o:	main.c $(HD)/param.h $(HD)/user.h $(HD)/proc.h $(HD)/text.h $(HD)/inode.h $(HD)/seg.h
malloc.o:	malloc.c $(HD)/param.h $(HD)/systm.h
nami.o:	nami.c $(HD)/param.h $(HD)/inode.h $(HD)/user.h $(HD)/systm.h $(HD)/buf.h
pipe.o:	pipe.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/inode.h $(HD)/file.h $(HD)/reg.h
prf.o:	prf.c $(HD)/param.h $(HD)/seg.h $(HD)/buf.h $(HD)/systm.h
pwbsys.o:	pwbsys.c $(HD)/param.h $(HD)/buf.h $(HD)/filsys.h $(HD)/inode.h \
	$(HD)/systm.h $(HD)/user.h $(HD)/reg.h $(HD)/var.h
rdwri.o:	rdwri.c $(HD)/param.h $(HD)/inode.h $(HD)/user.h $(HD)/buf.h \
	$(HD)/conf.h $(HD)/systm.h
sig.o:	sig.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/proc.h \
	$(HD)/inode.h $(HD)/reg.h $(HD)/text.h $(HD)/seg.h $(HD)/var.h
slp.o:	slp.c $(HD)/param.h $(HD)/user.h $(HD)/proc.h $(HD)/text.h $(HD)/systm.h \
	$(HD)/file.h $(HD)/inode.h $(HD)/buf.h $(HD)/var.h
subr.o:	subr.c $(HD)/param.h $(HD)/inode.h $(HD)/user.h $(HD)/buf.h $(HD)/systm.h
sys1.o:	sys1.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/proc.h $(HD)/buf.h $(HD)/reg.h \
	$(HD)/inode.h $(HD)/seg.h $(HD)/var.h
sys2.o:	sys2.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/reg.h $(HD)/file.h $(HD)/inode.h
sys3.o:	sys3.c $(HD)/param.h $(HD)/systm.h $(HD)/reg.h $(HD)/buf.h $(HD)/filsys.h \
	$(HD)/user.h $(HD)/inode.h $(HD)/file.h $(HD)/conf.h $(HD)/var.h
sys4.o:	sys4.c $(HD)/param.h $(HD)/user.h $(HD)/reg.h $(HD)/inode.h $(HD)/systm.h \
	$(HD)/proc.h $(HD)/var.h
text.o:	text.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/proc.h $(HD)/text.h \
	$(HD)/inode.h $(HD)/buf.h $(HD)/seg.h $(HD)/var.h
trap.o:	trap.c $(HD)/param.h $(HD)/systm.h $(HD)/user.h $(HD)/proc.h $(HD)/reg.h $(HD)/seg.h
D)/file.h $(HD)/inode.h
sys3.o:	sys3.c $(HD)/param.h $(HD)/systm.h $(HD)/reg.h $(HD)/buf.h $(HD)/filsys.h \
	$(HD)/user.h $(HD)/inode.h $#include "../hd/param.h"
#include "../hd/systm.h"

/*
 * Allocate 'size' units from the given
 * map. Return the base of the allocated
 * space.
 * In a map, the addresses are increasing and the
 * list is terminated by a 0 size.
 * The core map unit is 64 bytes; the swap map unit
 * is 512 bytes.
 * Algorithm is first-fit.
 */
malloc(mp, size)
struct map *mp;
{
	register int a;
	register struct map *bp;

	for (bp=mp; bp->m_size; bp++) {
		if (bp->m_size >= size) {
			a = bp->m_addr;
			bp->m_addr =+ size;
			if ((bp->m_size =- size) == 0)
				do {
					bp++;
					(bp-1)->m_addr = bp->m_addr;
				} while ((bp-1)->m_size = bp->m_size);
			return(a);
		}
	}
	return(0);
}

/*
 * Free the previously allocated space aa
 * of size units into the specified map.
 * Sort aa into map and combine on
 * one or both ends if possible.
 */
mfree(mp, size, aa)
struct map *mp;
char *aa;
{
	register struct map *bp;
	register int t;
	register char *a;

	a = aa;
	if ((bp = mp)==coremap && runin) {
		runin = 0;
		wakeup(&runin);		/* Wake scheduler when freeing core */
	}
	for (; bp->m_addr<=a && bp->m_size!=0; bp++);
	if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
		(bp-1)->m_size =+ size;
		if (a+size == bp->m_addr) {
			(bp-1)->m_size =+ bp->m_size;
			while (bp->m_size) {
				bp++;
				(bp-1)->m_addr = bp->m_addr;
				(bp-1)->m_size = bp->m_size;
			}
		}
	} else {
		if (a+size == bp->m_addr && bp->m_size) {
			bp->m_addr =- size;
			bp->m_size =+ size;
		} else if (size) do {
			t = bp->m_addr;
			bp->m_addr = a;
			a = t;
			t = bp->m_size;
			bp->m_size = size;
			bp++;
		} while (size = t);
	}
}
e!=0; bp++);
	if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
		(bp-1)->m_size =+ size;
		if (a+size == bp->m_addr) {
			(bp-1)->m_size =+ bp->m_size;
			while (bp->m_size) {
				bp++;
				(bp-1)->m_addr = bp->m_addr;
				(bp-1)->m_size = bp->m_size;
			}
		}
	} else {
		if (a+size == bp->m_addr && bp->m_size) {
			bp->m_addr =- size;
			bp->m_size =+ size;
		} else if (size) do {
			t = bp->m_addr;
			bp->m_addr = a;
			a = t;
#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/buf.h"

/*
 * Convert a pathname into a pointer to
 * an inode. Note that the inode is locked.
 *
 * func = function called to get next char of name
 *	&uchar if name is in user space
 *	&schar if name is in system space
 * flag = 0 if name is sought
 *	1 if name is to be created
 *	2 if name is to be deleted
 */
namei(func, flag)
int (*func)();
{
	register struct inode *dp;
	register c;
	register char *cp;
	int eo, *bp;

	/*
	 * If name starts with '/' start from
	 * root; otherwise start from current dir.
	 */

	dp = u.u_cdir;
	if((c=(*func)()) == '/')
		dp = rootdir;
	iget(dp->i_dev, dp->i_number);
	while(c == '/')
		c = (*func)();
	if(c == '\0' && flag != 0) {
		u.u_error = ENOENT;
		goto out;
	}

cloop:
	/*
	 * Here dp contains pointer
	 * to last component matched.
	 */

	if(u.u_error)
		goto out;
	if(c == '\0')
		return(dp);

	/*
	 * If there is another component,
	 * dp must be a directory and
	 * must have x permission.
	 */

	if((dp->i_mode&IFMT) != IFDIR || dp->i_nlink==0) {
		u.u_error = ENOTDIR;
		goto out;
	}
	if(access(dp, IEXEC))
		goto out;

	/*
	 * Gather up name into
	 * users' dir buffer.
	 */

	cp = &u.u_dbuf[0];
	while(c!='/' && c!='\0' && u.u_error==0) {
		if(cp < &u.u_dbuf[DIRSIZ])
			*cp++ = c;
		c = (*func)();
	}
	while(cp < &u.u_dbuf[DIRSIZ])
		*cp++ = '\0';
	while(c == '/')
		c = (*func)();
	if(u.u_error)
		goto out;

	/*
	 * Set up to search a directory.
	 */

	u.u_offset[1] = 0;
	u.u_offset[0] = 0;
	u.u_segflg = 1;
	eo = 0;
	u.u_count = ldiv(dp->i_size1, DIRSIZ+2);
	bp = NULL;

eloop:

	/*
	 * If at the end of the directory,
	 * the search failed. Report what
	 * is appropriate as per flag.
	 */

	if(u.u_count == 0) {
		if(bp != NULL)
			brelse(bp);
		if(flag==1 && c=='\0') {
			if(access(dp, IWRITE))
				goto out;
			u.u_pdir = dp;
			if(eo)
				u.u_offset[1] = eo-DIRSIZ-2; else
				bmap(dp,ldiv(u.u_offset[1],512));	/* check space */
			if (u.u_error)
				goto out;
			return(NULL);
		}
		u.u_error = ENOENT;
		goto out;
	}

	/*
	 * If offset is on a block boundary,
	 * read the next directory block.
	 * Release previous if it exists.
	 */

	if((u.u_offset[1]&0777) == 0) {
		if(bp != NULL)
			brelse(bp);
		bp = bread(dp->i_dev,
			bmap(dp, ldiv(u.u_offset[1], 512)));
	}

	/*
	 * Note first empty directory slot
	 * in eo for possible creat.
	 * String compare the directory entry
	 * and the current component.
	 * If they do not match, go back to eloop.
	 */

	bcopy(bp->b_addr+(u.u_offset[1]&0777), &u.u_dent, (DIRSIZ+2)/2);
	u.u_offset[1] =+ DIRSIZ+2;
	if (u.u_offset[1]==0)
		u.u_error = EFBIG;
	u.u_count--;
	if(u.u_dent.u_ino == 0) {
		if(eo == 0)
			eo = u.u_offset[1];
		goto eloop;
	}
	for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)
		if(*cp != cp[u.u_dent.u_name - u.u_dbuf])
			goto eloop;

	/*
	 * Here a component matched in a directory.
	 * If there is more pathname, go back to
	 * cloop, otherwise return.
	 */

	if(bp != NULL)
		brelse(bp);
	if(flag==2 && c=='\0') {
		if(access(dp, IWRITE))
			goto out;
		return(dp);
	}
	bp = dp->i_dev;
	iput(dp);
	dp = iget(bp, u.u_dent.u_ino);
	if(dp == NULL)
		return(NULL);
	goto cloop;

out:
	iput(dp);
	return(NULL);
}

/*
 * Return the next character from the
 * kernel string pointed at by dirp.
 */
schar()
{

	return(*u.u_dirp++ & 0377);
}

/*
 * Return the next character from the
 * user string pointed at by dirp.
 */
uchar()
{
	register c;

	c = fubyte(u.u_dirp++);
	if(c == -1)
		u.u_error = EFAULT;
	return(c);
}
&& c=='\0')#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/reg.h"

/*
 * Max allowable buffering per pipe.
 * This is also the max size of the
 * file created to implement the pipe.
 * If this size is bigger than 4096,
 * pipes will be implemented in LARG
 * files, which is probably not good.
 */
#define	PIPSIZ	4096

/*
 * The sys-pipe entry.
 * Allocate an inode on the root device.
 * Allocate 2 file structures.
 * Put it all together with flags.
 */
pipe()
{
	register *ip, *rf, *wf;
	int r;

	ip = ialloc(rootdev);
	if(ip == NULL)
		return;
	rf = falloc();
	if(rf == NULL) {
		iput(ip);
		return;
	}
	r = u.u_ar0[R0];
	wf = falloc();
	if(wf == NULL) {
		rf->f_count = 0;
		u.u_ofile[r] = NULL;
		iput(ip);
		return;
	}
	u.u_ar0[R1] = u.u_ar0[R0];
	u.u_ar0[R0] = r;
	wf->f_flag = FWRITE|FPIPE;
	wf->f_inode = ip;
	rf->f_flag = FREAD|FPIPE;
	rf->f_inode = ip;
	ip->i_count = 2;
	ip->i_flag = IACC|IUPD;
	ip->i_mode = IALLOC;
}

/*
 * Read call directed to a pipe.
 */
readp(fp)
int *fp;
{
	register *rp, *ip;

	rp = fp;
	ip = rp->f_inode;

loop:
	/*
	 * Very conservative locking.
	 */

	plock(ip);
	/*
	 * If nothing in the pipe, wait.
	 */
	if (ip->i_size1==0) {
		/*
		 * If there are not both reader and
		 * writer active, return without
		 * satisfying read.
		 */
		prele(ip);
		if(ip->i_count < 2)
			return;
		ip->i_mode =| IREAD;
		sleep(ip+2, PPIPE);
		goto loop;
	}

	/*
	 * Read and return
	 */

	u.u_offset[0] = 0;
	u.u_offset[1] = rp->f_offset[1];
	readi(ip);
	rp->f_offset[1] = u.u_offset[1];
	/*
	 * If reader has caught up with writer, reset
	 * offset and size to 0.
	 */
	if (rp->f_offset[1] == ip->i_size1) {
		rp->f_offset[1] = 0;
		ip->i_size1 = 0;
		if (ip->i_mode&IWRITE) {
			ip->i_mode =& ~IWRITE;
			wakeup(ip+1);
		}
	}
	prele(ip);
}

/*
 * Write call directed to a pipe.
 */
writep(fp)
{
	register *rp, *ip, c;

	rp = fp;
	ip = rp->f_inode;
	c = u.u_count;

loop:

	/*
	 * If all done, return.
	 */

	plock(ip);
	if(c == 0) {
		prele(ip);
		u.u_count = 0;
		return;
	}

	/*
	 * If there are not both read and
	 * write sides of the pipe active,
	 * return error and signal too.
	 */

	if(ip->i_count < 2) {
		prele(ip);
		u.u_error = EPIPE;
		psignal(u.u_procp, SIGPIPE);
		return;
	}

	/*
	 * If the pipe is full,
	 * wait for reads to deplete
	 * and truncate it.
	 */

	if(ip->i_size1 == PIPSIZ) {
		ip->i_mode =| IWRITE;
		prele(ip);
		sleep(ip+1, PPIPE);
		goto loop;
	}

	/*
	 * Write what is possible and
	 * loop back.
	 */

	u.u_offset[0] = 0;
	u.u_offset[1] = ip->i_size1;
	u.u_count = min(c, PIPSIZ-u.u_offset[1]);
	c =- u.u_count;
	writei(ip);
	prele(ip);
	if(ip->i_mode&IREAD) {
		ip->i_mode =& ~IREAD;
		wakeup(ip+2);
	}
	goto loop;
}

/*
 * Lock a pipe.
 * If its already locked,
 * set the WANT bit and sleep.
 */
plock(ip)
int *ip;
{
	register *rp;

	rp = ip;
	while(rp->i_flag&ILOCK) {
		rp->i_flag =| IWANT;
		sleep(rp, PPIPE);
	}
	rp->i_flag =| ILOCK;
}

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also used
 * to unlock inodes in general.
 */
prele(ip)
int *ip;
{
	register *rp;

	rp = ip;
	rp->i_flag =& ~ILOCK;
	if(rp->i_flag&IWANT) {
		rp->i_flag =& ~IWANT;
		wakeup(rp);
	}
}
akeup(ip+2);
	}
	goto loop;
}

/*
 * Lock a pipe.
 * If its already locked,
 * set the WANT bit and sleep.
 */
plock(ip)
int *ip;
{
	register *rp;

	rp = ip;
	while(rp->i_flag&ILOCK) {
		rp->i_flag =| IWANT;
		sleep(rp, PPIPE);
	}
	rp->i_flag =| ILOCK;
}

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also us#
#include "../hd/param.h"
#include "../hd/seg.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Address and structure of the
 * KL-11 console device registers.
 */
struct
{
	int	rsr;
	int	rbr;
	int	xsr;
	int	xbr;
};

/*
 * In case console is off,
 * panicstr contains argument to last
 * call to panic.
 */

char	*panicstr;

/*
 * Scaled down version of C Library printf.
 * Only %s %l %d (==%l) %o are recognized.
 * Used to print diagnostic information
 * directly on console tty.
 * Since it is not interrupt driven,
 * all system activities are pretty much
 * suspended.
 * Printf should not be used for chit-chat.
 */
printf(fmt,x1)
char fmt[];
{
	register char *s;
	register *adx, c;

	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	c = *fmt++;
	if(c == 'd' || c == 'l' || c == 'o')
		printn(*adx, c=='o'? 8: 10);
	if(c == 's') {
		s = *adx;
		while(c = *s++)
			putchar(c);
	}
	adx++;
	goto loop;
}

/*
 * Print an unsigned integer in base b.
 */
printn(n, b)
{
	register a;

	if(a = ldiv(n, b))
		printn(a, b);
	putchar(lrem(n, b) + '0');
}

/*
 * Print a character on console.
 * Attempts to save and restore device
 * status.
 * If the switches are 0, all
 * printing is inhibited.
 */
putchar(c)
{
	register rc, s;

	rc = c;
	if(SW->integ == 0)
		return;
	while((KL->xsr&0200) == 0)
		;
	if(rc == 0)
		return;
	s = KL->xsr;
	KL->xsr = 0;
	KL->xbr = rc;
	if(rc == '\n') {
		putchar('\r');
		putchar(0177);
		putchar(0177);
	}
	putchar(0);
	KL->xsr = s;
}

/*
 * Panic is called on unresolvable
 * fatal errors.
 * It syncs, prints "panic: mesg" and
 * then loops.
 */
panic(s)
char *s;
{
	panicstr = s;
	update();
	printf("panic: %s\n", s);
	for(;;)
		idle();
}

/*
 * prdev prints a warning message of the
 * form "mesg on dev x/y".
 * x and y are the major and minor parts of
 * the device argument.
 */
prdev(str, dev)
{

	printf("%s on dev %l/%l\n", str, major(dev), minor(dev));
}

/*
 * deverr prints a diagnostic from
 * a device driver.
 * It prints the device, block number,
 * and an octal word (usually some error
 * status register) passed as argument.
 */
deverror(bp, o1, o2)
int *bp;
{
	register *rbp;

	if(SW->integ&01)
		return;
	rbp = bp;
	prdev("err", rbp->b_dev);
	printf("bn%l er%o %o\n", rbp->b_blkno, o1, o2);
}
 dev x/y".
 * x and y are the major and minor parts of
 * the device argument.
 */
prdev(str, dev)
{

	printf("%s on dev %l/%l\n", str, major(dev), minor(dev));
}

/*
 * deverr prints a diagnostic from
 * a device driver.
 * It prints the device, block number,
#
#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/inode.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/var.h"

pwbsys()
{
	extern uchar;
	register i;
	register *p;
	register struct buf *bp;

	switch(u.u_arg[0]) {

case 0:		/* uname */
	if (copyout(&pwbname, u.u_ar0[R0], 8))
		u.u_error = EFAULT;
	return;

case 1:		/* udata */
	if (u.u_ar0[R1]) {
		if(suser())
			i = copyin(u.u_ar0[R0],u.u_udata,32); else
			return;
	} else
		i = copyout(u.u_udata,u.u_ar0[R0],32);
	if (i)
		u.u_error = EFAULT;
	return;

case 2:		/* ustat */
	for(i=0; i<v.v_mount; i++) {
		p = &mount[i];
		if(p->m_bufp!=NULL && p->m_dev==u.u_ar0[R1]) {
			p = p->m_bufp->b_addr;
			if(copyout(&p->s_tfree, u.u_ar0[R0], 16))
				u.u_error = EFAULT;
			return;
		}
	}
	u.u_error = EINVAL;
	return;

case 3:		/* utime */
	if (!suser())
		return;
	u.u_dirp = u.u_ar0[R1];
	if ((p = namei(&uchar, 0))==NULL)
		return;
	if (getfs(p->i_dev)->s_ronly) {
		u.u_error = EROFS;
		return;
	}
	i = p->i_number+31;
	bp = bread(p->i_dev, ldiv(i,16));
	copyin (u.u_ar0[R0], bp->b_addr+32*lrem(i,16)+24, 8);
	p->i_flag =& ~(IACC|IUPD);
	bdwrite(bp);
	iput(p);
	return;

default:
	u.u_error = EFAULT;
	}
}
r;
			if(copyout(&p->s_tfree, u.u_ar0[R0], 16))
				u.u_error = EFAULT;
			return;
		}
	}
	u.u_error = EINVAL;
	return;

case 3:		/* utime */
	if (!suser())
		return;
	u.u_dirp = u.u_ar0[R1];
	if ((p = namei(&uchar, 0))==NULL)
		return;
	if (getfs(p->i_dev)->s_ronly) {
		u.u_error = EROFS;#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/conf.h"
#include "../hd/systm.h"

/*
 * Read the file corresponding to
 * the inode pointed at by the argument.
 * The actual read arguments are found
 * in the variables:
 *	u_base		core address for destination
 *	u_offset	byte offset in file
 *	u_count		number of bytes to read
 *	u_segflg	read to kernel/user/user I
 */
readi(aip)
struct inode *aip;
{
	int *bp;
	int lbn, bn, on;
	register dn, n;
	register struct inode *ip;

	ip = aip;
	if(u.u_count == 0)
		return;
	ip->i_flag =| IACC;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_read)(minor(ip->i_addr[0]));
		return;
	}

	do {
		lbn = bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			dn = dpcmp(ip->i_size0&0377, ip->i_size1,
				u.u_offset[0], u.u_offset[1]);
			if(dn <= 0)
				return;
			n = min(n, dn);
			if ((bn = bmap(ip, lbn)) == 0)
				return;
			dn = ip->i_dev;
		} else {
			dn = ip->i_addr[0];
			rablock = bn+1;
		}
		if ((ip->i_lastr+1) == lbn && (on+n) == 512)
			bp = breada(dn, bn, rablock);
		else
			bp = bread(dn, bn);
		if ((on+n) == 512)
			ip->i_lastr = lbn;
		if (bp->b_resid!=0)
			n = 0;
		iomove(bp, on, n, B_READ);
		brelse(bp);
	} while(u.u_error==0 && u.u_count && n);
}

/*
 * Write the file corresponding to
 * the inode pointed at by the argument.
 * The actual write arguments are found
 * in the variables:
 *	u_base		core address for source
 *	u_offset	byte offset in file
 *	u_count		number of bytes to write
 *	u_segflg	write to kernel/user/user I
 */
writei(aip)
struct inode *aip;
{
	int *bp;
	int n, on;
	register dn, bn;
	register struct inode *ip;

	ip = aip;
	ip->i_flag =| IACC|IUPD;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_write)(minor(ip->i_addr[0]));
		return;
	}
	if (u.u_count == 0)
		return;

	do {
		bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			if ((bn = bmap(ip, bn)) == 0)
				return;
			dn = ip->i_dev;
		} else
			dn = ip->i_addr[0];
		if(n == 512) 
			bp = getblk(dn, bn); else
			bp = bread(dn, bn);
		iomove(bp, on, n, B_WRITE);
		if(u.u_error != 0)
			brelse(bp); else
		if ((u.u_offset[1]&0777)==0)
			bawrite(bp); else
			bdwrite(bp);
		if(dpcmp(ip->i_size0&0377, ip->i_size1,
		  u.u_offset[0], u.u_offset[1]) < 0 &&
		  (ip->i_mode&(IFBLK&IFCHR)) == 0) {
			ip->i_size0 = u.u_offset[0];
			ip->i_size1 = u.u_offset[1];
		}
		ip->i_flag =| IUPD;
	} while(u.u_error==0 && u.u_count!=0);
}

/*
 * Return the logical maximum
 * of the 2 arguments.
 */
max(a, b)
char *a, *b;
{

	if(a > b)
		return(a);
	return(b);
}

/*
 * Return the logical minimum
 * of the 2 arguments.
 */
min(a, b)
char *a, *b;
{

	if(a < b)
		return(a);
	return(b);
}

/*
 * Move 'an' bytes at byte location
 * &bp->b_addr[o] to/from (flag) the
 * user/kernel (u.segflg) area starting at u.base.
 * Update all the arguments by the number
 * of bytes moved.
 *
 * There are 2 algorithms,
 * if source address, dest address and count
 * are all even in a user copy,
 * then the machine language copyin/copyout
 * is called.
 * If not, its done byte-by-byte with
 * cpass and passc.
 */
iomove(bp, o, an, flag)
struct buf *bp;
{
	register char *cp;
	register int n, t;

	if ((n = an)==0 || u.u_error)
		return;
	cp = bp->b_addr + o;
	if(u.u_segflg!=1 && ((n | cp | u.u_base)&01)==0) {
		if (flag==B_WRITE)
			if (u.u_segflg==0)
				cp = copyin(u.u_base, cp, n);
			else
				cp = copyiin(u.u_base, cp, n);
		else
			if (u.u_segflg==0)
				cp = copyout(cp, u.u_base, n);
			else
				cp = copyiout(cp, u.u_base, n);
		if (cp) {
			u.u_error = EFAULT;
			return;
		}
		u.u_base =+ n;
		dpadd(u.u_offset, n);
		u.u_count =- n;
		return;
	}
	if (flag==B_WRITE) {
		while(n--) {
			if ((t = cpass()) < 0)
				return;
			*cp++ = t;
		}
	} else
		while (n--)
			if(passc(*cp++) < 0)
				return;
}
1)==0) {
		if (flag==B_WRITE)
			if (u.u_segflg==0)
				cp = copyin(u.u_base, cp, n);
			else
#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/text.h"
#include "../hd/seg.h"
#include "../hd/var.h"

/*
 * Priority for tracing
 */
#define	IPCPRI	0

/*
 * Structure to access an array of integers.
 */
struct
{
	int	inta[];
};

/*
 * Tracing variables.
 * Used to pass trace command from
 * parent to child being traced.
 * This data base cannot be
 * shared and is locked
 * per user.
 */
struct
{
	int	ip_lock;
	int	ip_req;
	int	ip_addr;
	int	ip_data;
} ipc;

/*
 * Send the specified signal to
 * all processes with 'pgrp' as
 * process group.
 * Called by tty.c for quits and
 * interrupts.
 */
signal(apgrp, sig)
{
	register struct proc *p;
	register pgrp;

	if ((pgrp = apgrp)==0)
		return;
	for(p = &proc[0]; p < v.ve_proc; p++)
		if(p->p_pgrp == pgrp)
			psignal(p, sig);
}

/*
 * Send the specified signal to
 * the specified process.
 */
psignal(p, sig)
int *p;
char *sig;
{
	register *rp, a;

	a = sig;
	if(a > NSIG)
		return;
	rp = p;
	if(a)
		rp->p_sig =| 1<<(a-1);
	if(rp->p_pri > PUSER)
		rp->p_pri = PUSER;
	if(rp->p_stat == SSLEEP && rp->p_pri > 0)
		setrun(rp);
}

/*
 * Returns true if the current
 * process has a signal to process.
 * This is asked at least once
 * each time a process enters the
 * system.
 * A signal does not do anything
 * directly to a process; it sets
 * a flag that asks the process to
 * do something to itself.
 */
issig()
{
	register n;
	register struct proc *p;

	p = u.u_procp;
	while(p->p_sig) {
		n = fsig(p);
		if((u.u_signal[n-1]&1) == 0 || (p->p_flag&STRC))
			return(n);
		p->p_sig =& ~(1<<(n-1));
	}
	return(0);
}

/*
 * Enter the tracing STOP state.
 * In this state, the parent is
 * informed and the process is able to
 * receive commands from the parent.
 */
stop()
{
	register struct proc *pp, *cp;

loop:
	cp = u.u_procp;
	if(cp->p_ppid != 1)
	for (pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_pid == cp->p_ppid) {
			wakeup(pp);
			cp->p_stat = SSTOP;
			swtch();
			if ((cp->p_flag&STRC)==0 || procxmt())
				return;
			goto loop;
		}
	exit();
}

/*
 * Perform the action specified by
 * the current signal.
 * The usual sequence is:
 *	if(issig())
 *		psig();
 */
psig()
{
	register n, p;
	register *rp;

	rp = u.u_procp;
	if (rp->p_flag&STRC)
		stop();
	n = fsig(rp);
	if (n==0)
		return;
	rp->p_sig =& ~(1<<(n-1));
	if((p=u.u_signal[n-1]) != 0) {
		u.u_error = 0;
		if(n != SIGINS && n != SIGTRC)
			u.u_signal[n-1] = 0;
		n = u.u_ar0[R6] - 4;
		grow(n);
		suword(n+2, u.u_ar0[RPS]);
		suword(n, u.u_ar0[R7]);
		u.u_ar0[R6] = n;
		u.u_ar0[RPS] =& ~TBIT;
		u.u_ar0[R7] = p;
		return;
	}
	switch(n) {

	case SIGQIT:
	case SIGINS:
	case SIGTRC:
	case SIGIOT:
	case SIGEMT:
	case SIGFPT:
	case SIGBUS:
	case SIGSEG:
	case SIGSYS:
		u.u_arg[0] = n;
		if(core())
			n =+ 0200;
	}
	u.u_arg[0] = (u.u_ar0[R0]<<8) | n;
	exit();
}

/*
 * find the signal in bit-position
 * representation in p_sig.
 */
fsig(p)
struct proc *p;
{
	register n, i;
	register char *cp;

	n = p->p_sig;
	for(i=1; i<=NSIG; i++) {
		if(n & 1)
			return(i);
		n =>> 1;
	}
	return(0);
}

/*
 * Create a core image on the file "core"
 * If you are looking for protection glitches,
 * there are probably a wealth of them here
 * when this occurs to a suid command.
 *
 * It writes USIZE block of the
 * user.h area followed by the entire
 * data+stack segments.
 */
core()
{
	register s, *ip;
	extern schar;

	u.u_error = 0;
	u.u_dirp = "core";
	ip = namei(&schar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return(0);
		ip = maknode(0666);
		if (ip==NULL)
			return(0);
	}
	if(!access(ip, IWRITE) &&
	   (ip->i_mode&IFMT) == 0 &&
	   u.u_uid == u.u_ruid) {
		itrunc(ip);
		u.u_offset[0] = 0;
		u.u_offset[1] = 0;
		u.u_base = &u;
		u.u_count = USIZE*64;
		u.u_segflg = 1;
		writei(ip);
		s = u.u_procp->p_size - USIZE;
		estabur(0, s, 0, 0, RO);
		u.u_base = 0;
		u.u_count = s*64;
		u.u_segflg = 0;
		writei(ip);
	}
	iput(ip);
	return(u.u_error==0);
}

/*
 * grow the stack to include the SP
 * true return if successful.
 */

grow(sp)
char *sp;
{
	register a, si, i;

	if(sp >= -u.u_ssize*64)
		return(0);
	si = ldiv(-sp, 64) - u.u_ssize + SINCR;
	if(si <= 0)
		return(0);
	if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep, RO))
		return(0);
	expand(u.u_procp->p_size+si);
	a = u.u_procp->p_addr + u.u_procp->p_size;
	for(i=u.u_ssize; i; i--) {
		a--;
		copyseg(a-si, a);
	}
	for(i=si; i; i--)
		clearseg(--a);
	u.u_ssize =+ si;
	return(1);
}

/*
 * sys-trace system call.
 */
ptrace()
{
	register struct proc *p;
	register struct text *xp;

	if (u.u_arg[2] <= 0) {
		u.u_procp->p_flag =| STRC;
		return;
	}
	for (p=proc; p < v.ve_proc; p++) 
		if (p->p_stat==SSTOP
		 && p->p_pid==u.u_arg[0]
		 && p->p_ppid==u.u_procp->p_pid)
			goto found;
	u.u_error = ESRCH;
	return;

    found:
	while (ipc.ip_lock)
		sleep(&ipc, IPCPRI);
	ipc.ip_lock = p->p_pid;
	ipc.ip_data = u.u_ar0[R0];
	ipc.ip_addr = u.u_arg[1] & ~01;
	ipc.ip_req = u.u_arg[2];
	p->p_flag =& ~SWTED;
	setrun(p);
	while (ipc.ip_req > 0)
		sleep(&ipc, IPCPRI);
	u.u_ar0[R0] = ipc.ip_data;
	if (ipc.ip_req < 0)
		u.u_error = EIO;
	ipc.ip_lock = 0;
	wakeup(&ipc);
}

/*
 * Code that the child process
 * executes to implement the command
 * of the parent process in tracing.
 */
procxmt()
{
	register int i;
	register int *p;
	register struct text *xp;

	if (ipc.ip_lock != u.u_procp->p_pid)
		return(0);
	i = ipc.ip_req;
	ipc.ip_req = 0;
	wakeup(&ipc);
	switch (i) {

	/* read user I */
	case 1:
		if (fuibyte(ipc.ip_addr) == -1)
			goto error;
		ipc.ip_data = fuiword(ipc.ip_addr);
		break;

	/* read user D */
	case 2:
		if (fubyte(ipc.ip_addr) == -1)
			goto error;
		ipc.ip_data = fuword(ipc.ip_addr);
		break;

	/* read u */
	case 3:
		i = ipc.ip_addr;
		if (i<0 || i >= (USIZE<<6))
			goto error;
		ipc.ip_data = u.inta[i>>1];
		break;

	/* write user I */
	/* Must set up to allow writing */
	case 4:
		/*
		 * If text, must assure exclusive use
		 */
		if (xp = u.u_procp->p_textp) {
			if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
				goto error;
			xp->x_iptr->i_flag =& ~ITEXT;
		}
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RW);
		i = suiword(ipc.ip_addr, 0);
		suiword(ipc.ip_addr, ipc.ip_data);
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RO);
		if (i<0)
			goto error;
		if (xp)
			xp->x_flag =| XWRIT;
		break;

	/* write user D */
	case 5:
		if (suword(ipc.ip_addr, 0) < 0)
			goto error;
		suword(ipc.ip_addr, ipc.ip_data);
		break;

	/* write u */
	case 6:
		p = &u.inta[ipc.ip_addr>>1];
		if (p >= u.u_fsav && p < &u.u_fsav[25])
			goto ok;
		for (i=0; i<9; i++)
			if (p == &u.u_ar0[regloc[i]])
				goto ok;
		goto error;
	ok:
		if (p == &u.u_ar0[RPS]) {
			ipc.ip_data =| 0170000;	/* assure user space */
			ipc.ip_data =& ~0340;	/* priority 0 */
		}
		*p = ipc.ip_data;
		break;

	/* set signal and continue */
	case 7:
		u.u_procp->p_sig = 0;
		psignal(u.u_procp, ipc.ip_data);
		return(1);

	/* force exit */
	case 8:
		exit();

	default:
	error:
		ipc.ip_req = -1;
	}
	return(0);
}
_addr>>1];
		if (p >= u.u_fsav && p < &u.u_fsav[25])
			goto ok;
		for (i=0; i<9; i++)
			if (p == &u.u_ar0[regloc[i]])
			#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/systm.h"
#include "../hd/file.h"
#include "../hd/inode.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Give up the processor till a wakeup occurs
 * on chan, at which time the process
 * enters the scheduling queue at priority pri.
 * The most important effect of pri is that when
 * pri<=0 a signal cannot disturb the sleep;
 * if pri>0 signals will be processed.
 * Callers of this routine must be prepared for
 * premature return, and check that the reason for
 * sleeping has gone away.
 */
sleep(chan, pri)
{
	register *rp, s;

	s = PS->integ;
	rp = u.u_procp;
	spl6();
	rp->p_stat = SSLEEP;
	rp->p_wchan = chan;
	rp->p_pri = pri;
	if(pri > 0) {
		if(issig()) {
			rp->p_wchan = 0;
			rp->p_stat = SRUN;
			spl0();
			goto psig;
		}
		spl0();
		swtch();
		if(issig())
			goto psig;
	} else {
		spl0();
		swtch();
	}
	PS->integ = s;
	return;

	/*
	 * If priority was low (>0) and
	 * there has been a signal,
	 * execute non-local goto to
	 * the qsav location.
	 * (see trap1/trap.c)
	 */
psig:
	aretu(u.u_qsav);
}

/*
 * Wake up all processes sleeping on chan.
 */
wakeup(chan)
{
	register struct proc *p;
	register c, i;

	c = chan;
	p = &proc[0];
	i = v.ve_proc;
	do {
		if(p->p_wchan == c && p->p_stat==SSLEEP)
			setrun(p);
		p++;
	} while(p != i);
}

setrq(p)
struct proc *p;
{
	register struct proc *q;
	register s;

	s = PS->integ;
	spl6();
	for(q=runq; q!=NULL; q=q->p_link)
		if(q == p) {
			printf("proc on q\n");
			goto out;
		}
	p->p_link = runq;
	runq = p;
out:
	PS->integ = s;
}

/*
 * Set the process running;
 * arrange for it to be swapped in if necessary.
 */
setrun(p)
{
	register struct proc *rp;

	rp = p;
	rp->p_wchan = 0;
	rp->p_stat = SRUN;
	setrq(p);
	if((rp->p_flag&SLOAD)==0) {
		rp->p_time = 0;
		if(runout != 0) {
			runout = 0;
			setrun(&proc[0]);
		}
	} else
		if(rp->p_pri < curpri)
			runrun++;
}

/*
 * Set user priority.
 * The rescheduling flag (runrun)
 * is set if the priority is better
 * than the currently running process.
 */
setpri(up)
{
	register *pp, p;

	pp = up;
	p = pp->p_cpu/4;
	p =+ PUSER + pp->p_nice;
	if(p > 127)
		p = 127;
	pp->p_pri = p;
	return(p);
}

/*
 * The main loop of the scheduling (swapping)
 * process.
 * The basic idea is:
 *  see if anyone wants to be swapped in;
 *  swap out processes until there is room;
 *  swap him in;
 *  repeat.
 * The runout flag is set whenever someone is swapped out.
 * Sched sleeps on it awaiting work.
 *
 * Sched sleeps on runin whenever it cannot find enough
 * core (by swapping out or otherwise) to fit the
 * selected swapped process.  It is awakend when the
 * core situation changes and in any event once per second.
 */
sched()
{
	register struct proc *rp, *p;
	register outage, inage;
	int swapri, a;

	/*
	 * find user to swap in;
	 * of users ready, select one out longest
	 */

loop:
	spl6();
	outage = -1;
	for(rp = &proc[0]; rp < v.ve_proc; rp++)
	if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
	    rp->p_time > outage) {
		p = rp;
		outage = rp->p_time;
	}
	/*
	 * If there is no one there, wait.
	 */
	if (outage<0) {
		runout++;
		sleep(&runout, PSWP);
		goto loop;
	}
	spl0();

	/*
	 * See if there is core for that process;
	 * if so, swap it in.
	 */

	if (swapin(p))
		goto loop;

	/*
	 * none found.
	 */

	spl6();
	swapri = 0;
	inage = 0;
	for(rp = &proc[0]; rp < v.ve_proc; rp++) {
		if ((rp->p_flag&(SSYS|SLOCK|SLOAD))!=SLOAD)
			continue;
		if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
			continue;
		if(rp->p_stat==SSLEEP || rp->p_stat==SSTOP) {
			a = (rp->p_pri>>1) + rp->p_time;
			if(a>swapri) {
				p = rp;
				swapri = a;
			}
		} else
		if(swapri<=0 && rp->p_stat==SRUN && rp->p_time>inage) {
			p = rp;
			inage = rp->p_time;
		}
	}
	spl0();
	/*
	 * Swap found user out if sleeping,
	 * or if he has spent at least 4 seconds in core and
	 * the swapped-out process has spent at 2 seconds out.
	 * Otherwise wait a bit and try again.
	 */
	if (swapri>0 || (outage>=2 && inage>=4)) {
		p->p_flag =& ~SLOAD;
		xswap(p, 1, 0);
		goto loop;
	}
	spl6();
	runin++;
	sleep(&runin, PSWP);
	goto loop;

}

/*
 * Swap a process in.
 * Allocate data and possible text separately.
 * It would be better to do largest first.
 */
swapin(pp)
struct proc *pp;
{
	register struct proc *p;
	register struct text *xp;
	register int a;
	int x;

	p = pp;
	if ((a = malloc(coremap, p->p_size)) == NULL)
		return(0);
	if (xp = p->p_textp) {
		xlock(xp);
		if (xp->x_ccount==0) {
			if ((x = malloc(coremap, xp->x_size)) == NULL) {
				xunlock(xp);
				mfree(coremap, p->p_size, a);
				return(0);
			}
			xp->x_caddr = x;
			if ((xp->x_flag&XLOAD)==0)
				swap(xp->x_daddr,x,xp->x_size,B_READ);
		}
		xp->x_ccount++;
		xunlock(xp);
	}
	swap(p->p_addr, a, p->p_size, B_READ);
	mfree(swapmap, ctob(p->p_size), p->p_addr);
	p->p_addr = a;
	p->p_flag =| SLOAD;
	p->p_time = 0;
	return(1);
}

qswtch()
{

	setrq(u.u_procp);
	swtch();
}

/*
 * This routine is called to reschedule the CPU.
 * if the calling process is not in RUN state,
 * arrangements for it to restart must have
 * been made elsewhere, usually by calling via sleep.
 */
swtch()
{
	register n;
	register struct proc *p, *q;
	static struct proc *pp, *pq;

	/*
	 * Remember stack of caller
	 * and switch to schedulers stack.
	 */
	savu(u.u_rsav);
	retu(proc[0].p_addr);

loop:
	spl6();
	runrun = 0;
	pp = NULL;
	q = NULL;
	n = 128;
	/*
	 * Search for highest-priority runnable process
	 */
	for(p=runq; p!=NULL; p=p->p_link) {
		if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {
			if(p->p_pri <= n) {
				pp = p;
				pq = q;
				n = p->p_pri;
			}
		}
		q = p;
	}
	/*
	 * If no process is runnable, idle.
	 */
	p = pp;
	if(p == NULL) {
		idle();
		spl0();
		goto loop;
	}
	q = pq;
	if(q == NULL)
		runq = p->p_link; else
		q->p_link = p->p_link;
	curpri = n;
	spl0();
	/*
	 * Switch to stack of the new process and set up
	 * his segmentation registers.
	 */
	retu(p->p_addr);
	sureg();
	/*
	 * If the new process paused because it was
	 * swapped out, set the stack level to the last call
	 * to savu(u_ssav).  This means that the return
	 * which is executed immediately after the call to aretu
	 * actually returns from the last routine which did
	 * the savu.
	 */
	if(p->p_flag&SSWAP) {
		p->p_flag =& ~SSWAP;
		aretu(u.u_ssav);
	}
	/*
	 * The value returned here has many subtle implications.
	 * See the newproc comments.
	 */
	return(1);
}

/*
 * Create a new process-- the internal version of
 * sys fork.
 * It returns 1 in the new process.
 * How this happens is rather hard to understand.
 * The essential fact is that the new process is created
 * in such a way that appears to have started executing
 * in the same call to newproc as the parent;
 * but in fact the code that runs is that of swtch.
 * The subtle implication of the returned value of swtch
 * (see above) is that this is the value that newproc's
 * caller in the new process sees.
 */
newproc()
{
	int a1, a2;
	struct proc *p, *up;
	register struct proc *rpp;
	register *rip, n;
	struct proc *pend;

	p = NULL;
	/*
	 * First, just locate a slot for a process
	 * and copy the useful info from this process into it.
	 * The panic "cannot happen" because fork has already
	 * checked for the existence of a slot.
	 */
retry:
	mpid++;
	if(mpid < 0) {
		mpid = 0;
		goto retry;
	}
	for(rpp = &proc[0]; rpp < &proc[v.v_proc]; rpp++) {
		if(rpp->p_stat == NULL) {
			if(p == NULL)
				p = rpp;
		} else
			pend = rpp;
		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
			goto retry;
	}
	if ((rpp = p)==NULL)
		panic("no procs");
	if (rpp > pend)
		pend = rpp;
	pend++;
	v.ve_proc = pend;

	/*
	 * make proc entry for new proc
	 */

	rip = u.u_procp;
	up = rip;
	rpp->p_stat = SRUN;
	rpp->p_clktim = 0;
	rpp->p_flag = SLOAD;
	rpp->p_uid = rip->p_uid;
	rpp->p_pgrp = rip->p_pgrp;
	rpp->p_nice = rip->p_nice;
	rpp->p_textp = rip->p_textp;
	rpp->p_pid = mpid;
	rpp->p_ppid = rip->p_pid;
	rpp->p_time = 0;
	rpp->p_cpu = 0;

	/*
	 * make duplicate entries
	 * where needed
	 */

	for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)
		if((rpp = *rip++) != NULL)
			rpp->f_count++;
	if((rpp=up->p_textp) != NULL) {
		rpp->x_count++;
		rpp->x_ccount++;
	}
	u.u_cdir->i_count++;
	/*
	 * Partially simulate the environment
	 * of the new process so that when it is actually
	 * created (by copying) it will look right.
	 */
	savu(u.u_rsav);
	rpp = p;
	u.u_procp = rpp;
	rip = up;
	n = rip->p_size;
	a1 = rip->p_addr;
	rpp->p_size = n;
	a2 = malloc(coremap, n);
	/*
	 * If there is not enough core for the
	 * new process, swap out the current process to generate the
	 * copy.
	 */
	if(a2 == NULL) {
		rip->p_stat = SIDL;
		rpp->p_addr = a1;
		savu(u.u_ssav);
		xswap(rpp, 0, 0);
		rpp->p_flag =| SSWAP;
		rip->p_stat = SRUN;
	} else {
	/*
	 * There is core, so just copy.
	 */
		rpp->p_addr = a2;
		while(n--)
			copyseg(a1++, a2++);
	}
	u.u_procp = rip;
	setrq(rpp);
	return(0);
}

/*
 * Change the size of the data+stack regions of the process.
 * If the size is shrinking, it's easy-- just release the extra core.
 * If it's growing, and there is core, just allocate it
 * and copy the image, taking care to reset registers to account
 * for the fact that the system's stack has moved.
 * If there is no core, arrange for the process to be swapped
 * out after adjusting the size requirement-- when it comes
 * in, enough core will be allocated.
 * Because of the ssave and SSWAP flags, control will
 * resume after the swap in swtch, which executes the return
 * from this stack level.
 *
 * After the expansion, the caller will take care of copying
 * the user's stack towards or away from the data area.
 */
expand(newsize)
{
	int i, n;
	register *p, a1, a2;

	p = u.u_procp;
	n = p->p_size;
	p->p_size = newsize;
	a1 = p->p_addr;
	if(n >= newsize) {
		mfree(coremap, n-newsize, a1+newsize);
		return;
	}
	savu(u.u_rsav);
	a2 = malloc(coremap, newsize);
	if(a2 == NULL) {
		savu(u.u_ssav);
		xswap(p, 1, n);
		p->p_flag =| SSWAP;
		qswtch();
		/* no return */
	}
	p->p_addr = a2;
	for(i=0; i<n; i++)
		copyseg(a1+i, a2++);
	mfree(coremap, n, a1);
	retu(p->p_addr);
	sureg();
}
ck towards or away from the data area.
 */
expand(newsize)
{
	int i, n;
	register *p, a1, a2;
#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Bmap defines the structure of file system storage
 * by returning the physical block number on a device given the
 * inode and the logical block number in a file.
 * When convenient, it also leaves the physical
 * block number of the next block of the file in rablock
 * for use in read-ahead.
 */
bmap(ip, bn)
struct inode *ip;
int bn;
{
	register *bp, *bap, nb;
	int *nbp, d, i;

	d = ip->i_dev;
	if(bn & ~03777) {
		u.u_error = EFBIG;
		return(0);
	}

	if((ip->i_mode&ILARG) == 0) {

		/*
		 * small file algorithm
		 */

		if((bn & ~7) != 0) {

			/*
			 * convert small to large
			 */

			if ((bp = alloc(d)) == NULL)
				return(NULL);
			bap = bp->b_addr;
			for(i=0; i<8; i++) {
				*bap++ = ip->i_addr[i];
				ip->i_addr[i] = 0;
			}
			ip->i_addr[0] = bp->b_blkno;
			bdwrite(bp);
			ip->i_mode =| ILARG;
			ip->i_flag =| IUPD;
			goto large;
		}
		nb = ip->i_addr[bn];
		if(nb == 0 && (bp = alloc(d)) != NULL) {
			bdwrite(bp);
			nb = bp->b_blkno;
			ip->i_addr[bn] = nb;
			ip->i_flag =| IUPD;
		}
		rablock = 0;
		if (bn<7)
			rablock = ip->i_addr[bn+1];
		return(nb);
	}

	/*
	 * large file algorithm
	 */

    large:
	i = bn>>8;
	if((nb=ip->i_addr[i]) == 0) {
		if ((bp = alloc(d)) == NULL)
			return(NULL);
		ip->i_addr[i] = bp->b_blkno;
		ip->i_flag =| IUPD;
	} else
		bp = bread(d, nb);
	bap = bp->b_addr;

	/*
	 * normal indirect fetch
	 */

	i = bn & 0377;
	if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) {
		nb = nbp->b_blkno;
		bap[i] = nb;
		bdwrite(nbp);
		bdwrite(bp);
	} else
		brelse(bp);
	rablock = 0;
	if(i < 255)
		rablock = bap[i+1];
	return(nb);
}

/*
 * Pass back  c  to the user at his location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * on the last character of the user's read.
 * u_base is in the user address space unless u_segflg is set.
 */
passc(c)
char c;
{
	register id;

	if((id = u.u_segflg) == 1)
		*u.u_base = c;
	else
		if(id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(u.u_count == 0? -1: 0);
}

/*
 * Pick up and return the next character from the user's
 * write call at location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * when u_count is exhausted.  u_base is in the user's
 * address space unless u_segflg is set.
 */
cpass()
{
	register c, id;

	if(u.u_count == 0)
		return(-1);
	if((id = u.u_segflg) == 1)
		c = *u.u_base;
	else
		if((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(c&0377);
}

/*
 * Routine which sets a user error; placed in
 * illegal entries in the bdevsw and cdevsw tables.
 */
nodev()
{

	u.u_error = ENODEV;
}

/*
 * Null routine; placed in insignificant entries
 * in the bdevsw and cdevsw tables.
 */
nulldev()
{
}

/*
 * copy count words from from to to.
 */
bcopy(from, to, count)
int *from, *to;
{
	register *a, *b, c;

	a = from;
	b = to;
	c = count;
	do
		*b++ = *a++;
	while(--c);
}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(c&0377);
}

/*
 * Routine which sets a user error; placed in
 * illegal entries in the bdevsw and cdevsw tables.
 */
nodev()
{

	u.u_error = ENODEV;
}

/*
 * Null routine; placed in insignificant entries
 * in the bdevsw and cdevsw tables.
 */
nulldev()
{
}

/*
 * copy count words from from to to.
 */
bcop#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/buf.h"
#include "../hd/reg.h"
#include "../hd/inode.h"
#include "../hd/seg.h"
#include "../hd/var.h"

exec()
{
	register nc;
	register char *cp;
	register struct buf *bp;
	int na, bno, ucp, ap, c, ip;

	if((ip = gethead()) == NULL)
		return;
	bp = na = nc = 0;
	/* collect arglist */
	if ((bno = malloc(swapmap,(NCARGS+511)/512)) == 0)
		panic("Out of swap");
	if (u.u_arg[1]) while(ap = fuword(u.u_arg[1])) {
		na++;
		if(ap == -1)
			u.u_error = EFAULT;
		u.u_arg[1] =+ 2;
		do {
			if (nc >= NCARGS-1)
				u.u_error = E2BIG;
			if ((c = fubyte(ap++)) < 0)
				u.u_error = EFAULT;
			if (u.u_error)
				goto bad;
			if ((nc&0777) == 0) {
				if (bp)
					bawrite(bp);
				bp = getblk(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			nc++;
			*cp++ = c;
		} while (c>0);
	}
	if (bp)
		bawrite(bp);
	bp = 0;
	if((nc&1) != 0)
		nc++;
	ip = getxfile(ip, nc+2*na);
	if (u.u_error)
		goto bad;
	/* copy back arglist */
	ucp = -nc;
	ap = ucp - na*2 - 4;
	u.u_ar0[R6] = ap;
	suword(ap, na);
	nc = 0;
	while(na--) {
		suword(ap=+2, ucp);
		do {
			if ((nc&0777) == 0) {
				if (bp)
					brelse(bp);
				bp = bread(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			subyte(ucp++, (c = *cp++));
			nc++;
		} while(c&0377);
	}
	suword(ap+2, -1);
	setregs();
bad:
	if (bp)
		brelse(bp);
	if(ip)
		iput(ip);
	mfree(swapmap, (NCARGS+511)/512, bno);
}

/*
 * Read in and set up memory for executed file.
 */
getxfile(ip,nargc)
register struct inode *ip;
{
	register i, as, ds;

	u.u_prof[3] = 0;
	xfree();
	as = nargc>>6;
	u.u_ssize = SSIZE+as;
	u.u_dsize = ((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize+63)>>6) & 01777;
	u.u_tsize = ((u.u_exdata.ux_tsize+63)>>6) & 01777;
	i = USIZE+u.u_dsize+u.u_ssize;
	expand(i);
	i =- as;
	ds = USIZE+((u.u_exdata.ux_dsize>>6)&01777);
	while(--i >= ds)
		clearseg(u.u_procp->p_addr+i);
	xalloc(ip);
	/* read in data segment */
	estabur(0, u.u_dsize, 0, 0, RO);
	u.u_base = 0;
	u.u_offset[1] = 020+u.u_exdata.ux_tsize;
	u.u_count = u.u_exdata.ux_dsize;
	readi(ip);
	if (u.u_count!=0)
		u.u_error = EFAULT;
	/*
	 * set SUID/SGID protections, if no tracing
	 */
	if ((u.u_procp->p_flag&STRC)==0) {
		if(ip->i_mode&ISUID)
			if(u.u_uid != 0) {
				u.u_uid = ip->i_uid;
				u.u_procp->p_uid = ip->i_uid;
			}
		if(ip->i_mode&ISGID)
			u.u_gid = ip->i_gid;
	}
	u.u_sep = (u.u_exdata.ux_mag == 0411)?1:0;
	estabur(u.u_tsize, u.u_dsize, u.u_ssize,u.u_sep,RO);
	iput(ip);
	if (u.u_error)
		psignal(u.u_procp, SIGKIL);
	return(0);
}


gethead()
{
	register struct inode *ip;
	register sep, ts;
	long	ls;
	int	ds;
	extern int uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if (access(ip, IEXEC) ||
	   (ip->i_mode & IFMT) != 0 ||
	   (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
		u.u_error = EACCES;
		goto bad;
	}
	/*
	 * read in first few bytes of file for segment sizes
	 * ux_mag = 407/410/411
	 *  407 is plain executable
	 *  410 is RO text
	 *  411 is separated ID
	 */
	u.u_base = &u.u_exdata;
	u.u_count = sizeof(u.u_exdata);
	u.u_offset[0] = u.u_offset[1] = 0;
	u.u_segflg = 1;
	readi(ip);
	u.u_segflg = 0;
	if(u.u_error)
		goto bad;
	if (u.u_count!=0) {
		u.u_error = ENOEXEC;
		goto bad;
	}
	sep = 0;
	ls = 63;
	dpadd(&ls, u.u_exdata.ux_dsize);
	dpadd(&ls, u.u_exdata.ux_bsize);
	if(u.u_exdata.ux_mag == 0407) {
		dpadd(&ls, u.u_exdata.ux_tsize);
		u.u_exdata.ux_dsize =+ u.u_exdata.ux_tsize;
		u.u_exdata.ux_tsize = 0;
	} else if (u.u_exdata.ux_mag == 0411)
		sep++;
	else if (u.u_exdata.ux_mag != 0410) {
		u.u_error = ENOEXEC;
		goto bad;
	}
	if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
		u.u_error = ETXTBSY;
		goto bad;
	}
	ts = (u.u_exdata.ux_tsize>>6) & 01777;
	if (u.u_exdata.ux_tsize&077)
		ts++;
	ds = ls>>6;
	if(checkur(ts,ds,SSIZE,sep)==0)
		return(ip);
bad:
	iput(ip);
	return(NULL);
}

setregs()
{
	register int *rp;
	register char *cp;

	for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
		if((*rp & 1) == 0)
			*rp = 0;
	for(cp = &regloc[0]; cp < &regloc[6];)
		u.u_ar0[*cp++] = 0;
	u.u_ar0[R7] = u.u_exdata.ux_entloc & ~01;
	for(rp = &u.u_fsav[0]; rp < &u.u_fsav[25];)
		*rp++ = 0;

}

/*
 * exit system call:
 * pass back caller's r0
 */
rexit()
{

	u.u_arg[0] = u.u_ar0[R0] << 8;
	exit();
}

/*
 * Release resources.
 * Save u. area for parent to look at.
 * Enter zombie state.
 * Wake up parent and init processes,
 * and dispose of children.
 */
exit()
{
	register int *a;
	register struct proc *p, *q;

	p = u.u_procp;
	p->p_flag =& ~STRC;
	p->p_clktim = 0;
	for(a = &u.u_signal[0]; a < &u.u_signal[NSIG];)
		*a++ = 1;
	for(a = &u.u_ofile[0]; a < &u.u_ofile[NOFILE]; a++)
		if (*a) {
			closef(*a);
			*a = NULL;
		}
	plock(u.u_cdir);
	iput(u.u_cdir);
	xfree();
	mfree(coremap, p->p_size, p->p_addr);
	p->p_stat = SZOMB;
	p->xp_xstat = u.u_arg[0];
	p->xp_utime = u.u_cutime + u.u_utime;
	p->xp_stime = u.u_cstime + u.u_stime;
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(q->p_ppid == p->p_pid) {
			wakeup(&proc[1]);
			q->p_ppid = 1;
			if (q->p_stat==SSTOP)
				setrun(q);
		}
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(p->p_ppid == q->p_pid) {
			wakeup(q);
			swtch();
			/* no return */
		}
	printf("Init proc dead");
	swtch();
}

/*
 * Wait system call.
 * Search for a terminated (zombie) child,
 * finally lay it to rest, and collect its status.
 * Look also for stopped (traced) children,
 * and pass back status from them.
 */
wait()
{
	register f;
	register struct proc *p;

	f = 0;

loop:
	for(p = &proc[0]; p < v.ve_proc; p++)
	if(p->p_ppid == u.u_procp->p_pid) {
		f++;
		if(p->p_stat == SZOMB) {
			u.u_ar0[R0] = p->p_pid;
			u.u_ar0[R1] = p->xp_xstat;
			u.u_cutime =+ p->xp_utime;
			u.u_cstime =+ p->xp_stime;
			p->p_stat = NULL;
			p->p_pid = 0;
			p->p_ppid = 0;
			p->p_sig = 0;
			p->p_pgrp = 0;
			p->p_flag = 0;
			p->p_wchan = 0;
			return;
		}
		if(p->p_stat == SSTOP) {
			if((p->p_flag&SWTED) == 0) {
				p->p_flag =| SWTED;
				u.u_ar0[R0] = p->p_pid;
				u.u_ar0[R1] = (fsig(p)<<8) | 0177;
				return;
			}
			continue;
		}
	}
	if(f) {
		sleep(u.u_procp, PWAIT);
		goto loop;
	}
	u.u_error = ECHILD;
}

/*
 * fork system call.
 */
fork()
{
	register struct proc *p1, *p2;
	register a;

	/*
	 * Make sure there's enough swap space for max
	 * core image, thus reducing chances of running out
	 */
	if ((a = malloc(swapmap, ctob(MAXMEM))) == 0) {
		u.u_error = ENOMEM;
		goto out;
	}
	mfree(swapmap, ctob(MAXMEM), a);
	p1 = u.u_procp;
	for(p2 = &proc[0]; p2 < &proc[v.v_proc]; p2++)
		if(p2->p_stat == NULL)
			goto found;
	u.u_error = EAGAIN;
	goto out;

found:
	if(newproc()) {
		u.u_ar0[R0] = p1->p_pid;
		u.u_cstime = 0;
		u.u_stime = 0;
		u.u_cutime = 0;
		u.u_utime = 0;
		return;
	}
	u.u_ar0[R0] = p2->p_pid;

out:
	u.u_ar0[R7] =+ 2;
}

/*
 * break system call.
 *  -- bad planning: "break" is a dirty word in C.
 */
sbreak()
{
	register a, n, d;
	int i;

	/*
	 * set n to new data size
	 * set d to new-old
	 * set n to new total size
	 */

	n = (((u.u_arg[0]+63)>>6) & 01777);
	if(!u.u_sep)
		n =- ctos(u.u_tsize) * 128;
	if(n < 0)
		n = 0;
	d = n - u.u_dsize;
	n =+ USIZE+u.u_ssize;
	if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO))
		return;
	u.u_dsize =+ d;
	if(d > 0)
		goto bigger;
	a = u.u_procp->p_addr + n - u.u_ssize;
	i = n;
	n = u.u_ssize;
	while(n--) {
		copyseg(a-d, a);
		a++;
	}
	expand(i);
	return;

bigger:
	expand(n);
	a = u.u_procp->p_addr + n;
	n = u.u_ssize;
	while(n--) {
		a--;
		copyseg(a-d, a);
	}
	while(d--)
		clearseg(--a);
}
rg[0]+63)>>6) & 01777);
	if(!u.u_sep)
		n =- ctos(u.u_tsize) * 128;
	if(n < 0)
		n = 0;
	d = n - u.u_dsize;
	n =+ USIZE+u.u_ssize;
	if(estabur(u.u_tsize, #
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/file.h"
#include "../hd/inode.h"

/*
 * read system call
 */
read()
{
	rdwr(FREAD);
}

/*
 * write system call
 */
write()
{
	rdwr(FWRITE);
}

/*
 * common code for read and write calls:
 * check permissions, set base, count, and offset,
 * and switch out to readi, writei, or pipe code.
 */
rdwr(mode)
{
	register *fp, *ip, m;

	m = mode;
	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if((fp->f_flag&m) == 0) {
		u.u_error = EBADF;
		return;
	}
	u.u_base = u.u_arg[0];
	u.u_count = u.u_arg[1];
	u.u_segflg = 0;
	if(fp->f_flag&FPIPE) {
		if(m==FREAD)
			readp(fp); else
			writep(fp);
	} else {
		ip = fp->f_inode;
		u.u_offset[1] = fp->f_offset[1];
		u.u_offset[0] = fp->f_offset[0];
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			plock(ip);
		if(m==FREAD)
			readi(ip); else
			writei(ip);
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			prele(ip);
		dpadd(fp->f_offset, u.u_arg[1]-u.u_count);
	}
	u.u_ar0[R0] = u.u_arg[1]-u.u_count;
}

/*
 * open system call
 */
open()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	u.u_arg[1]++;
	open1(ip, u.u_arg[1], 0);
}

/*
 * creat system call
 */
creat()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return;
		ip = maknode(u.u_arg[1]&07777&(~ISVTX));
		if (ip==NULL)
			return;
		open1(ip, FWRITE, 2);
	} else
		open1(ip, FWRITE, 1);
}

/*
 * common code for open and creat.
 * Check permissions, allocate an open file structure,
 * and call the device open routine if any.
 */
open1(ip, mode, trf)
int *ip;
{
	register struct file *fp;
	register *rip, m;
	int i;

	rip = ip;
	m = mode;
	if(trf != 2) {
		if(m&FREAD)
			access(rip, IREAD);
		if(m&FWRITE) {
			access(rip, IWRITE);
			if((rip->i_mode&IFMT) == IFDIR)
				u.u_error = EISDIR;
		}
	}
	if(u.u_error)
		goto out;
	if(trf == 1)
		itrunc(rip);
	prele(rip);
	if ((fp = falloc()) == NULL)
		goto out;
	fp->f_flag = m&(FREAD|FWRITE);
	fp->f_inode = rip;
	i = u.u_ar0[R0];
	if (rip->i_mode&(IFCHR&IFBLK))
		openi(rip, m&FWRITE);
	if(u.u_error == 0)
		return;
	u.u_ofile[i] = NULL;
	fp->f_count--;

out:
	iput(rip);
}

/*
 * close system call
 */
close()
{
	register *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	u.u_ofile[u.u_ar0[R0]] = NULL;
	closef(fp);
}

/*
 * seek system call
 */
seek()
{
	int n[2];
	register *fp, t;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if(fp->f_flag&FPIPE) {
		u.u_error = ESPIPE;
		return;
	}
	t = u.u_arg[1];
	if(t > 2) {
		n[1] = u.u_arg[0]<<9;
		n[0] = u.u_arg[0]>>7;
		if(t == 3)
			n[0] =& 0777;
	} else {
		n[1] = u.u_arg[0];
		n[0] = 0;
		if(t!=0 && n[1]<0)
			n[0] = -1;
	}
	switch(t) {

	case 1:
	case 4:
		n[0] =+ fp->f_offset[0];
		dpadd(n, fp->f_offset[1]);
		break;

	default:
		n[0] =+ fp->f_inode->i_size0&0377;
		dpadd(n, fp->f_inode->i_size1);

	case 0:
	case 3:
		;
	}
	if (n[0] & ~0777)
		u.u_error = EFBIG;
	else {
		fp->f_offset[1] = n[1];
		fp->f_offset[0] = n[0];
	}
}

/*
 * Tell -- discover offset of file R/W pointer
 */
tell()
{
	register struct file *fp;

	if (fp = getf(u.u_ar0[R0])) {
		u.u_ar0[R0] = fp->f_offset[0];
		u.u_ar0[R1] = fp->f_offset[1];
	}
}

/*
 * link system call
 */
link()
{
	register *ip, *xp;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if(ip->i_nlink >= 127) {
		u.u_error = EMLINK;
		goto out;
	}
	if((ip->i_mode&IFMT)==IFDIR && !suser())
		goto out;
	/*
	 * Unlock to avoid possibly hanging the namei.
	 * Sadly, this means races. (Suppose someone
	 * deletes the file in the meantime?)
	 * Nor can it be locked again later
	 * because then there will be deadly
	 * embraces.
	 */
	prele(ip);
	u.u_dirp = u.u_arg[1];
	xp = namei(&uchar, 1);
	if(xp != NULL) {
		u.u_error = EEXIST;
		iput(xp);
	}
	if(u.u_error)
		goto out;
	if(u.u_pdir->i_dev != ip->i_dev) {
		iput(u.u_pdir);
		u.u_error = EXDEV;
		goto out;
	}
	wdir(ip);
	ip->i_nlink++;
	ip->i_flag =| IUPD;

out:
	iput(ip);
}

/*
 * mknod system call
 */
mknod()
{
	register *ip;
	extern uchar;

	if(suser()) {
		ip = namei(&uchar, 1);
		if(ip != NULL) {
			u.u_error = EEXIST;
			goto out;
		}
	}
	if(u.u_error)
		return;
	ip = maknode(u.u_arg[1]);
	if (ip==NULL)
		return;
	ip->i_addr[0] = u.u_arg[2];

out:
	iput(ip);
}

/*
 * sleep system call
 * not to be confused with the sleep internal routine.
 */
sslep()
{
	long d;

	spl7();
	d = time + u.u_ar0[R0];
	while (time < d) {
		if (tout<=time || d<tout)
			tout = d;
		sleep(&tout, PSLEP);
	}
	spl0();
}

/*
 * access system call
 */
saccess()
{
	extern uchar;
	register svuid, svgid;
	register *ip;

	svuid = u.u_uid;
	svgid = u.u_gid;
	u.u_uid = u.u_ruid;
	u.u_gid = u.u_rgid;
	ip = namei(&uchar, 0);
	if (ip != NULL) {
		if (u.u_arg[1]&(IREAD>>6))
			access(ip, IREAD);
		if (u.u_arg[1]&(IWRITE>>6))
			access(ip, IWRITE);
		if (u.u_arg[1]&(IEXEC>>6))
			access(ip, IEXEC);
		iput(ip);
	}
	u.u_uid = svuid;
	u.u_gid = svgid;
}
 < d) {
		if (tout<=time || d<tout)
			tout = d;
		sleep(&tout, PSLEP);
	}
	spl0();
}

/*
 * access system call
 */
saccess()
{
	extern uchar;
	register svui#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/reg.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/var.h"

/*
 * the fstat system call.
 */
fstat()
{
	register *fp, *base;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	base	= u.u_arg[0];
	stat1(fp->f_inode, base);
	if (fp->f_flag&FPIPE)		/* correct if pipe */
		suword(&base[5],fp->f_inode->i_size1-fp->f_offset[1]);
}

/*
 * the stat system call.
 */
stat()
{
	register ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	stat1(ip, u.u_arg[1]);
	iput(ip);
}

/*
 * The basic routine for fstat and stat:
 * get the inode and pass appropriate parts back.
 */
stat1(ip, ub)
int *ip;
{
	register i, *bp, *cp;

	iupdat(ip);
	bp = bread(ip->i_dev, ldiv(ip->i_number+31, 16));
	cp = bp->b_addr + 32*lrem(ip->i_number+31, 16) + 24;
	ip = &(ip->i_dev);
	for(i=0; i<14; i++) {
		if (suword(ub, *ip) != *ip++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	for(i=0; i<4; i++) {
		if (suword(ub, *cp) != *cp++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	brelse(bp);
}

/*
 * the dup system call.
 */
dup()
{
	register i, *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if ((i = ufalloc()) < 0)
		return;
	u.u_ofile[i] = fp;
	fp->f_count++;
}

/*
 * the mount system call.
 */
smount()
{
	int d;
	register *ip;
	register struct mount *mp, *smp;
	extern uchar;

	if(!suser())
		return;
	d = getmdev();
	if(u.u_error)
		return;
	u.u_dirp = u.u_arg[1];
	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if(ip->i_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0)
		goto out;
	smp = NULL;
	for(mp = &mount[0]; mp < v.ve_mount; mp++) {
		if(mp->m_bufp != NULL) {
			if(d == mp->m_dev)
				goto out;
		} else
		if(smp == NULL)
			smp = mp;
	}
	if(smp == NULL)
		goto out;
	(*bdevsw[major(d)].d_open)(minor(d), !u.u_arg[2]);
	if(u.u_error)
		goto out;
	mp = bread(d, 1);
	if(u.u_error) {
		brelse(mp);
		goto out1;
	}
	smp->m_inodp = ip;
	smp->m_dev = d;
	smp->m_bufp = getblk(NODEV);
	bcopy(mp->b_addr, smp->m_bufp->b_addr, 256);
	smp = smp->m_bufp->b_addr;
	smp->s_ilock = 0;
	smp->s_flock = 0;
	smp->s_ninode = 0;
	smp->s_ronly = u.u_arg[2] & 1;
	brelse(mp);
	ip->i_flag =| IMOUNT;
	prele(ip);
	return;

out:
	u.u_error = EBUSY;
out1:
	iput(ip);
}

/*
 * the umount system call.
 */
sumount()
{
	int d;
	register struct inode *ip;
	register struct mount *mp;

	if(!suser())
		return;
	update();
	d = getmdev();
	if(u.u_error)
		return;
	for(mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp!=NULL && d==mp->m_dev)
			goto found;
	u.u_error = EINVAL;
	return;

found:
	for(ip = &inode[0]; ip < v.ve_inode; ip++)
		if(ip->i_number!=0 && d==ip->i_dev) {
			u.u_error = EBUSY;
			return;
		}
	(*bdevsw[major(d)].d_close)(minor(d), 0);
	ip = mp->m_inodp;
	ip->i_flag =& ~IMOUNT;
	plock(ip);
	iput(ip);
	ip = mp->m_bufp;
	mp->m_bufp = NULL;
	brelse(ip);
}

/*
 * Common code for mount and umount.
 * Check that the user's argument is a reasonable
 * thing on which to mount, and return the device number if so.
 */
getmdev()
{
	register d, *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return(NODEV);
	if((ip->i_mode&IFMT) != IFBLK)
		u.u_error = ENOTBLK;
	d = ip->i_addr[0];
	if(major(ip->i_addr[0]) >= bdevcnt)
		u.u_error = ENXIO;
	iput(ip);
	return(d);
}
lag =& ~IMOUNT;
	plock(ip);
	iput(ip);
	ip = mp->m_bufp;
	mp->m_bufp = NULL;
	brelse(ip);
}

/*
 * Common code for mount and umount.
 * Check that the user's argument is a reasonable
 * thing on which to mount, and return #
/*
 * Everything in this file is a routine implementing a system call.
 */

#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/inode.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/var.h"

getswit()
{

	u.u_ar0[R0] = SW->integ;
}

gtime()
{
	u.u_ar0[R0] = time.hiword;
	u.u_ar0[R1] = time.loword;
}

stime()
{
	if(suser()) {
		time.hiword = u.u_ar0[R0];
		time.loword = u.u_ar0[R1];
		wakeup(&tout);
	}
}

setuid()
{
	register uid;

	uid = u.u_ar0[R0].lobyte;
	if(u.u_ruid == uid.lobyte || suser()) {
		u.u_uid = uid;
		u.u_procp->p_uid = uid;
		u.u_ruid = uid;
	}
}

getuid()
{

	u.u_ar0[R0].lobyte = u.u_ruid;
	u.u_ar0[R0].hibyte = u.u_uid;
}

setgid()
{
	register gid;

	gid = u.u_ar0[R0].lobyte;
	if(u.u_rgid == gid.lobyte || suser()) {
		u.u_gid = gid;
		u.u_rgid = gid;
	}
}

getgid()
{

	u.u_ar0[R0].lobyte = u.u_rgid;
	u.u_ar0[R0].hibyte = u.u_gid;
}

getpid()
{
	u.u_ar0[R0] = u.u_procp->p_pid;
	u.u_ar0[R1] = u.u_procp->p_pgrp;
}

setpgrp()
{
	u.u_procp->p_pgrp = u.u_procp->p_pid;
}

sync()
{

	update();
}

nice()
{
	register n;

	n = u.u_ar0[R0];
	if(n > 20)
		n = 20;
	if(n < 0 && !suser())
		n = 0;
	u.u_procp->p_nice = n;
}

/*
 * Unlink system call.
 * Hard to avoid races here, especially
 * in unlinking directories.
 */
unlink()
{
	register *ip, *pp;
	extern uchar;

	pp = namei(&uchar, 2);
	if(pp == NULL)
		return;
	/*
	 * Check for unlink(".")
	 * to avoid hanging on the iget
	 */
	if (pp->i_number != u.u_dent.u_ino)
		ip = iget(pp->i_dev, u.u_dent.u_ino);
	else {
		ip = pp;
		ip->i_count++;
	}
	if(ip == NULL)
		goto out1;
	if((ip->i_mode&IFMT)==IFDIR && !suser())
		goto out;
	/*
	 * Don't unlink a mounted file.
	 */
	if (ip->i_dev != pp->i_dev) {
		u.u_error = EBUSY;
		goto out;
	}
	if (ip->i_flag&ITEXT && ip->i_nlink==1) {
		u.u_error = ETXTBSY;
		goto out;
	}
	u.u_offset[1] =- DIRSIZ+2;
	u.u_base = &u.u_dent;
	u.u_count = DIRSIZ+2;
	u.u_dent.u_ino = 0;
	writei(pp);
	ip->i_nlink--;
	ip->i_flag =| IUPD;

out:
	iput(ip);
out1:
	iput(pp);
}

chdir()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if((ip->i_mode&IFMT) != IFDIR) {
		u.u_error = ENOTDIR;
	bad:
		iput(ip);
		return;
	}
	if(access(ip, IEXEC))
		goto bad;
	prele(ip);
	plock(u.u_cdir);
	iput(u.u_cdir);
	u.u_cdir = ip;
}

chmod()
{
	register *ip, a;

	if ((ip = owner()) == NULL)
		return;
	ip->i_mode =& ~07777;
	a = u.u_arg[1];
	if (u.u_uid) {
		a =& ~ISVTX;
		if (u.u_gid != ip->i_gid)
			a =& ~ISGID;
	}
	ip->i_mode =| a&07777;
	ip->i_flag =| IUPD;
	iput(ip);
}

chown()
{
	register *ip;

	if ((ip = owner()) == NULL)
		return;
	ip->i_uid = u.u_arg[1].lobyte;
	ip->i_gid = u.u_arg[1].hibyte;
	if(u.u_uid != 0)
		ip->i_mode =& ~(ISUID|ISGID);
	ip->i_flag =| IUPD;
	iput(ip);
}

ssig()
{
	register a;

	a = u.u_arg[0];
	if(a<=0 || a>NSIG || a==SIGKIL) {
		u.u_error = EINVAL;
		return;
	}
	u.u_ar0[R0] = u.u_signal[a-1];
	u.u_signal[a-1] = u.u_arg[1];
	u.u_procp->p_sig =& ~(1<<(a-1));
}

kill()
{
	register struct proc *p;
	register a, f;

	f = 0;
	a = u.u_ar0[R0];
	if (a>0)
		p = &proc[0]; else
		p = &proc[2];
	for(; p < v.ve_proc; p++) {
		if(a > 0 && p->p_pid != a)
			continue;
		if(a == 0 && p->p_pgrp != u.u_procp->p_pgrp)
			continue;
		if(u.u_uid != 0 && u.u_uid != p->p_uid)
			if (a>0) {
				u.u_error = EPERM;
				return;
			} else
				continue;
		f++;
		psignal(p, u.u_arg[0]);
	}
	if(f == 0)
		u.u_error = ESRCH;
}

times()
{
	register *p;

	for(p = &u.u_utime; p  < &u.u_utime+4;) {
		suword(u.u_arg[0], *p++);
		u.u_arg[0] =+ 2;
	}
}

profil()
{

	u.u_prof[0] = u.u_arg[0] & ~1;	/* base of sample buf */
	u.u_prof[1] = u.u_arg[1];	/* size of same */
	u.u_prof[2] = u.u_arg[2];	/* pc offset */
	u.u_prof[3] = (u.u_arg[3]>>1) & 077777; /* pc scale */
}

/*
 * alarm clock signal
 */
alarm()
{
	register c, *p;

	p = u.u_procp;
	c = p->p_clktim;
	p->p_clktim = u.u_ar0[R0];
	u.u_ar0[R0] = c;
}

/*
 * indefinite wait.
 * no one should wakeup(&u)
 */
pause()
{

	for(;;)
		sleep(&u, PSLEP);
}
;) {
		suword(u.u_arg[0], *p++);
		u.u_arg[0] =+ 2;
	}
}

profil()
{

	u.u_prof[0] = u.u_arg[0#
/*
 * This table is the switch used to transfer
 * to the appropriate routine for processing a system call.
 * Each row contains the number of arguments expected
 * and a pointer to the routine.
 */
extern	nullsys(),rexit(),fork(),read(),write(),open(),close(),wait(),creat(),link();
extern	unlink(),exec(),chdir(),gtime(),mknod(),chmod(),chown(),sbreak(),stat(),seek();
extern	getpid(),smount(),sumount(),setuid(),getuid(),stime(),ptrace(),alarm(),fstat(),pause();
extern	stty(),gtty(),saccess(),nice(),sslep(),sync(),kill(),getswit(),setpgrp();
extern	tell(),dup(),pipe(),times(),profil(),setgid(),getgid(),ssig(),pwbsys(),nosys();
int	sysent[]
{
	0, &nullsys,			/*  0 = indir */
	0, &rexit,			/*  1 = exit */
	0, &fork,			/*  2 = fork */
	2, &read,			/*  3 = read */
	2, &write,			/*  4 = write */
	2, &open,			/*  5 = open */
	0, &close,			/*  6 = close */
	0, &wait,			/*  7 = wait */
	2, &creat,			/*  8 = creat */
	2, &link,			/*  9 = link */
	1, &unlink,			/* 10 = unlink */
	2, &exec,			/* 11 = exec */
	1, &chdir,			/* 12 = chdir */
	0, &gtime,			/* 13 = time */
	3, &mknod,			/* 14 = mknod */
	2, &chmod,			/* 15 = chmod */
	2, &chown,			/* 16 = chown */
	1, &sbreak,			/* 17 = break */
	2, &stat,			/* 18 = stat */
	2, &seek,			/* 19 = seek */
	0, &getpid,			/* 20 = getpid */
	3, &smount,			/* 21 = mount */
	1, &sumount,			/* 22 = umount */
	0, &setuid,			/* 23 = setuid */
	0, &getuid,			/* 24 = getuid */
	0, &stime,			/* 25 = stime */
	3, &ptrace,			/* 26 = ptrace */
	0, &alarm,			/* 27 = alarm */
	1, &fstat,			/* 28 = fstat */
	0, &pause,			/* 29 = pause */
	0, &nosys,			/* 30 = smdate */
	1, &stty,			/* 31 = stty */
	1, &gtty,			/* 32 = gtty */
	2, &saccess,			/* 33 = access */
	0, &nice,			/* 34 = nice */
	0, &sslep,			/* 35 = sleep */
	0, &sync,			/* 36 = sync */
	1, &kill,			/* 37 = kill */
	0, &getswit,			/* 38 = switch */
	0, &setpgrp,			/* 39 = setpgrp */
	0, &tell,			/* 40 = tell */
	0, &dup,			/* 41 = dup */
	0, &pipe,			/* 42 = pipe */
	1, &times,			/* 43 = times */
	4, &profil,			/* 44 = prof */
	0, &nosys,			/* 45 = tiu */
	0, &setgid,			/* 46 = setgid */
	0, &getgid,			/* 47 = getgid */
	2, &ssig,			/* 48 = sig */
	0, &nosys,			/* 49 = reserved for USG */
	0, &nosys,			/* 50 = reserved for USG */
	0, &nosys,			/* 51 = x */
	0, &nosys,			/* 52 = x */
	0, &nosys,			/* 53 = x */
	0, &nosys,			/* 54 = x */
	0, &nosys,			/* 55 = x */
	0, &nosys,			/* 56 = x */
	1, &pwbsys,			/* 57 = pwbsys */
	0, &nosys,			/* 58 = x */
	0, &nosys,			/* 59 = x */
	0, &nosys,			/* 60 = x */
	0, &nosys,			/* 61 = x */
	0, &nosys,			/* 62 = x */
	0, &nosys			/* 63 = x */
};

/*
 * Dummy entry for illegal system calls
 */

int badent[] {
	0, &nosys
};
s,			/* 49 = reserved for USG */
	0, &nosys,			/* 50 = reserved for USG */
	0, &nosys,			/* 51 = x */
	0, &nosys,			/* 52 = x */
	0, &nosys,			/* 53 = x */
	0, &nosys,			/* 54 = x */
	0, &nosys,			/* 55 = x */
	0, &nosys,			/* 56 = x */
	1, &pwbsys,			/* 57 = pwbsys */
	0, &nosys,			/* 58 = x */
	0, &nosys,			/* 59 = x */
	0, &nosys,			/* 60 = x */
	0, &nosys,			/* 61 = x */
	0, &nosys,	#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/inode.h"
#include "../hd/buf.h"
#include "../hd/seg.h"
#include "../hd/var.h"

/*
 * Swap out process p.
 * The ff flag causes its core to be freed--
 * it may be off when called to create an image for a
 * child process in newproc.
 * Os is the old size of the data area of the process,
 * and is supplied during core expansion swaps.
 *
 * panic: out of swap space
 */
xswap(rp, ff, os)
register *rp;
{
	register a;

	if(os == 0)
		os = rp->p_size;
	a = malloc(swapmap, ctob(rp->p_size));
	if(a == NULL)
		panic("out of swap space");
	rp->p_flag =| SLOCK;
	xccdec(rp->p_textp);
	swap(a, rp->p_addr, os, B_WRITE);
	if(ff)
		mfree(coremap, os, rp->p_addr);
	rp->p_addr = a;
	rp->p_flag =& ~(SLOAD|SLOCK);
	rp->p_time = 0;
	if(runout) {
		runout = 0;
		wakeup(&runout);
	}
}

/*
 * relinquish use of the shared text segment
 * of a process.
 */
xfree()
{
	register struct text *xp;
	register struct inode *ip;

	if((xp=u.u_procp->p_textp) == NULL)
		return;
	xlock(xp);
	u.u_procp->p_textp = NULL;
	xp->x_flag =& ~XLOCK;
	ip = xp->x_iptr;
	if(--xp->x_count==0 && (ip->i_mode&ISVTX)==0) {
		xp->x_iptr = NULL;
		mfree(swapmap, ctob(xp->x_size), xp->x_daddr);
		mfree(coremap, xp->x_size, xp->x_caddr);
		ip->i_flag =& ~ITEXT;
		if (ip->i_flag&ILOCK)
			ip->i_count--;
		else
			iput(ip);
	} else
		xccdec(xp);
}

/*
 * Attach to a shared text segment.
 * If there is no shared text, just return.
 * If there is, hook up to it:
 * if it is not currently being used, it has to be read
 * in from the inode (ip); the written bit is set to force it
 * to be written out as appropriate.
 * If it is being used, but is not currently in core,
 * a swap has to be done to get it back.
 */
xalloc(ip)
int *ip;
{
	register struct text *xp;
	register *rp, ts;

	if(u.u_exdata.ux_tsize == 0)
		return;
	rp = NULL;
	for (xp = &text[0]; xp < v.ve_text; xp++) {
		if(xp->x_iptr == NULL) {
			if(rp == NULL)
				rp = xp;
			continue;
		}
		if(xp->x_iptr == ip) {
			xlock(xp);
			xp->x_count++;
			u.u_procp->p_textp = xp;
			if (xp->x_ccount == 0)
				xexpand(xp);
			else
				xp->x_ccount++;
			xunlock(xp);
			return;
		}
	}
	if((xp=rp) == NULL) {
		printf("out of text");
		psignal(u.u_procp, SIGKIL);
		return;
	}
	xp->x_flag = XLOAD|XLOCK;
	xp->x_count = 1;
	xp->x_ccount = 0;
	xp->x_iptr = rp = ip;
	rp->i_flag =| ITEXT;
	rp->i_count++;
	ts = ((u.u_exdata.ux_tsize+63)>>6) & 01777;
	xp->x_size = ts;
	if((xp->x_daddr = malloc(swapmap, ctob(ts))) == NULL)
		panic("out of swap space");
	u.u_procp->p_textp = xp;
	xexpand(xp);
	estabur(ts, 0, 0, 0, RW);
	u.u_count = u.u_exdata.ux_tsize;
	u.u_offset[0] = 0;
	u.u_offset[1] = 020;
	u.u_base = 0;
	u.u_segflg = 2;
	u.u_procp->p_flag =| SLOCK;
	readi(rp);
	u.u_procp->p_flag =& ~SLOCK;
	u.u_segflg = 0;
	xp->x_flag = XWRIT;
}

/*
 * Assure core for text segment
 * Text must be locked to keep someone else from
 * freeing it in the meantime.
 * x_ccount must be 0.
 */
xexpand(xp)
register struct text *xp;
{
	if ((xp->x_caddr = malloc(coremap, xp->x_size)) != NULL) {
		if ((xp->x_flag&XLOAD)==0)
			swap(xp->x_daddr, xp->x_caddr, xp->x_size, B_READ);
		xp->x_ccount++;
		xunlock(xp);
		return;
	}
	savu(u.u_rsav);
	savu(u.u_ssav);
	xswap(u.u_procp, 1, 0);
	xunlock(xp);
	u.u_procp->p_flag =| SSWAP;
	qswtch();
	/* no return */
}

/*
 * Lock and unlock a text segment from swapping
 */
xlock(xp)
register struct text *xp;
{
	while(xp->x_flag&XLOCK) {
		xp->x_flag =| XWANT;
		sleep(xp, PSWP);
	}
	xp->x_flag =| XLOCK;
}

xunlock(xp)
register struct text *xp;
{
	if (xp->x_flag&XWANT)
		wakeup(xp);
	xp->x_flag =& ~(XLOCK|XWANT);
}

/*
 * Decrement the in-core usage count of a shared text segment.
 * When it drops to zero, free the core space.
 */
xccdec(xp)
register struct text *xp;
{
	if (xp==NULL || xp->x_ccount==0)
		return;
	xlock(xp);
	if (--xp->x_ccount==0) {
		if (xp->x_flag&XWRIT) {
			xp->x_flag =& ~XWRIT;
			swap(xp->x_daddr,xp->x_caddr,xp->x_size,B_WRITE);
		}
		mfree(coremap, xp->x_size, xp->x_caddr);
	}
	xunlock(xp);
}
(xp)
register struct text *xp;
{
	if (xp->x_flag&XWANT)
		wakeup(xp);
	xp->x_flag =& ~(XLOCK|XWANT);
}

/*
 * Decrement the in-core usage count of a shared text segment.
 * When it drops to zero, free the core space.
 */
xccdec(xp)
register struct text *xp;
{
	if (xp==NULL || xp->x_ccount==0)
		return;
	xlock(xp);
	if (--xp->x_ccount==0) {
		if (xp->x_flag&XWRIT) {
			xp->x_flag =& ~XWRIT;
			swap(xp->x_daddr,xp->x_caddr,xp->x_size,B_WRITE);
		}
		mfree(coremap, xp->x_size, xp->x_caddr);
#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/reg.h"
#include "../hd/seg.h"

#define	EBIT	1		/* user error bit in PS: C-bit */
#define	UMODE	0170000		/* user-mode bits in PS word */
#define	SETD	0170011		/* SETD instruction */
#define	SYS	0104400		/* sys (trap) instruction */
#define	USER	020		/* user-mode flag added to dev */
#define	MEMORY	0177740		/* 11/70 "memory" subsystem */
#define	NSYSENT	64		/* number of syscall entries */

/*
 * structure of the system entry table (sysent.c)
 */
struct sysent	{
	int	count;		/* argument count */
	int	(*call)();	/* name of handler */
} sysent[];

/*
 * Dummy entry for illegal system calls
 */

struct sysent badent[];

/*
 * Offsets of the user's registers relative to
 * the saved r0. See reg.h
 */
char	regloc[9]
{
	R0, R1, R2, R3, R4, R5, R6, R7, RPS
};

/*
 * Called from l40.s or l45.s when a processor trap occurs.
 * The arguments are the words saved on the system stack
 * by the hardware and software during the trap processing.
 * Their order is dictated by the hardware and the details
 * of C's calling sequence. They are peculiar in that
 * this call is not 'by value' and changed user registers
 * get copied back on return.
 * dev is the kind of trap that occurred.
 */
trap(dev, sp, r1, nps, r0, pc, ps)
{
	register i, a;
	register struct sysent *callp;

	savfp();
	if ((ps&UMODE) == UMODE)
		dev =| USER;
	u.u_ar0 = &r0;
	switch(dev) {

	/*
	 * Trap not expected.
	 * Usually a kernel mode bus error.
	 * The numbers printed are used to
	 * find the hardware PS/PC as follows.
	 * (all numbers in octal 18 bits)
	 *	address_of_saved_ps =
	 *		(ka6*0100) + aps - 0140000;
	 *	address_of_saved_pc =
	 *		address_of_saved_ps - 2;
	 */
	default:
		printf("ka6 = %o\n", *ka6);
		printf("aps = %o\n", &ps);
		printf("trap type %d\n", dev);
		panic("trap");

	case 0+USER: /* bus error */
		i = SIGBUS;
		break;

	/*
	 * If illegal instructions are not
	 * being caught and the offending instruction
	 * is a SETD, the trap is ignored.
	 * This is because C produces a SETD at
	 * the beginning of every program which
	 * will trap on CPUs without 11/45 FPU.
	 */
	case 1+USER: /* illegal instruction */
		if(fuiword(pc-2) == SETD && u.u_signal[SIGINS-1] == 0)
			goto out;
		i = SIGINS;
		break;

	case 2+USER: /* bpt or trace */
		i = SIGTRC;
		break;

	case 3+USER: /* iot */
		i = SIGIOT;
		break;

	case 5+USER: /* emt */
		i = SIGEMT;
		break;

	case 6+USER: /* sys call */
		u.u_error = 0;
		ps =& ~EBIT;
		if ((i=fuiword(pc-2)&0377) < NSYSENT)
			callp = &sysent[i]; else
			callp = &badent;
		if (callp == sysent) { /* indirect */
			a = fuiword(pc);
			pc =+ 2;
			i = fuword(a);
			if ((i & ~0377) != SYS || (i =& 0377) >= NSYSENT)
				callp = &badent; else
				callp = &sysent[i];
			for(i=0; i<callp->count; i++)
				u.u_arg[i] = fuword(a =+ 2);
		} else {
			for(i=0; i<callp->count; i++) {
				u.u_arg[i] = fuiword(pc);
				pc =+ 2;
			}
		}
		u.u_dirp = u.u_arg[0];
		trap1(callp->call);
		if(u.u_intflg)
			u.u_error = EINTR;
		if(u.u_error) {
			ps =| EBIT;
			r0 = u.u_error;
		}
		goto out;

	/*
	 * Since the floating exception is an
	 * imprecise trap, a user generated
	 * trap may actually come from kernel
	 * mode. In this case, a signal is sent
	 * to the current process to be picked
	 * up later.
	 */
	case 8: /* floating exception */
		psignal(u.u_procp, SIGFPT);
		return;

	case 8+USER:
		i = SIGFPT;
		break;

	/*
	 * If the user SP is below the stack segment,
	 * grow the stack automatically.
	 * This relies on the ability of the hardware
	 * to restart a half executed instruction.
	 * On the 11/40 this is not the case and
	 * the routine backup/l40.s may fail.
	 * The classic example is on the instruction
	 *	cmp	-(sp),-(sp)
	 */
	case 9+USER: /* segmentation exception */
		a = sp;
		if(backup(u.u_ar0) == 0)
		if(grow(a))
			goto out;
		i = SIGSEG;
		break;

	case 10:
	case 10+USER:
		if (cputype == 70) {
			printf("parity error\n");
			for(i=0; i<4; i++)
				printf("%o ", MEMORY->r[i]);
			printf("\n");
			MEMORY->r[2] = -1;
			if (dev&USER) {
				i = SIGBUS;
				break;
			}
		}
		panic("parity");

	}
	psignal(u.u_procp, i);

out:
	if(issig())
		psig();
	curpri = setpri(u.u_procp);
}

/*
 * Call the system-entry routine f (out of the
 * sysent table). This is a subroutine for trap, and
 * not in-line, because if a signal occurs
 * during processing, an (abnormal) return is simulated from
 * the last caller to savu(qsav); if this took place
 * inside of trap, it wouldn't have a chance to clean up.
 *
 * If this occurs, the return takes place without
 * clearing u_intflg; if it's still set, trap
 * marks an error which means that a system
 * call (like read on a typewriter) got interrupted
 * by a signal.
 */
trap1(f)
int (*f)();
{

	u.u_intflg = 1;
	savu(u.u_qsav);
	(*f)();
	u.u_intflg = 0;
}

/*
 * nonexistent system call-- signal bad system call.
 */
nosys()
{
	psignal(u.u_procp, SIGSYS);
}

/*
 * Ignored system call
 */
nullsys()
{
}

/*
 * Catch stray interrupts by using trace feature
 * trap through 0 looks like 42
 */
stray(dev, sp, r1, addr)
{
	printf("stray interrupt at %o\n",addr==042?0:addr-2);
}
n error which means that a system
 * call (like read on a typewriter) got interrupted
 * by a signal.
 */
trap1(f)
int (*f)();
{

	u.u_intflg = 1;
	savu(u.u_qsav);
	(*f)();
	u.u_intflg = 0;
}

/*
 * nonexistent system call-- signal bad system call.
 */
nosys()
{
	psignal(u.u_procp, SIGSYS);
}

/*
 * Ignored system call
 */
nullsys()
{
}

/*
 * Catch stray interrupts by using trace feature
 * trap through 0 looks like 42
 */

Jun 19 11:25 1978  buf.h Page 1


/*
 * Each buffer in the pool is usually doubly linked into 2 lists:
 * the device with which it is currently associated (always)
 * and also on a list of blocks available for allocation
 * for other use (usually).
 * The latter list is kept in last-used order, and the two
 * lists are doubly linked to make it easy to remove
 * a buffer from one list when it was found by
 * looking through the other.
 * A buffer is on the available list, and is liable
 * to be reassigned to another disk block, if and only
 * if it is not marked BUSY.  When a buffer is busy, the
 * available-list pointers can be used for other purposes.
 * Most drivers use the forward ptr as a link in their I/O active queue.
 * A buffer header contains all the information required to perform I/O.
 * Most of the routines which manipulate these things are in bio.c.
 */
struct buf
{
	int	b_flags;		/* see defines below */
	struct	buf *b_forw;		/* headed by devtab of b_dev */
	struct	buf *b_back;		/*  "  */
	struct	buf *av_forw;		/* position on free list, */
	struct	buf *av_back;		/*     if not BUSY*/
	int	b_dev;			/* major+minor device name */
	int	b_wcount;		/* transfer count (usu. words) */
	char	*b_addr;		/* low order core address */
	char	*b_xmem;		/* high order core address */
	char	*b_blkno;		/* block # on device */
	char	b_error;		/* returned after I/O */
	char	*b_resid;		/* words not transferred after error */
};

extern struct buf buf[];
extern struct buf bfreelist;
extern char buffers[][514];
/*
 * Each block device has a devtab, which contains private state stuff
 * and 2 list heads: the b_forw/b_back list, which is doubly linked
 * and has all the buffers currently associated with that major
 * device; and the d_actf/d_actl list, which is private to the
 * device but in fact is always used for the head and tail
 * of the I/O queue for the device.
 * Various routines in bio.c look at b_forw/b_back
 * (notice they are the same as in the buf structure)
 * but the rest is private to each device driver.
 */
struct devtab
{
	char	d_active;		/* busy flag */
	char	d_errcnt;		/* error count (for recovery) */
	struct	buf *b_forw;		/* first buffer for this dev */
	struct	buf *b_back;		/* last buffer for this dev */
	struct	buf *d_actf;		/* head of I/O queue */
	struct 	buf *d_actl;		/* tail of I/O queue */
};







Jun 19 11:25 1978  buf.h Page 2



/*
 * These flags are kept in b_flags.
 */
#define	B_WRITE	0	/* non-read pseudo-flag */
#define	B_READ	01	/* read when I/O occurs */
#define	B_DONE	02	/* transaction finished */
#define	B_ERROR	04	/* transaction aborted */
#define	B_BUSY	010	/* not on av_forw/back list */
#define	B_PHYS	020	/* Physical IO potentially using UNIBUS map */
#define	B_MAP	040	/* This block has the UNIBUS map allocated */
#define	B_WANTED 0100	/* issue wakeup when BUSY goes off */
#define	B_AGE	0200	/* delayed write for correct aging */
#define	B_ASYNC	0400	/* don't wait for I/O completion */
#define	B_DELWRI 01000	/* don't write till block leaves available list */
















































Jun 19 11:25 1978  conf.h Page 1


/*
 * Declaration of block device switch. Each entry (row) is
 * the only link between the main unix code and the driver.
 * The initialization of the device switches is in the file conf.c.
 */
struct	bdevsw
{
	int	(*d_open)();
	int	(*d_close)();
	int	(*d_strategy)();
	int	*d_tab;
} bdevsw[];

/*
 * Character device switch.
 */
struct	cdevsw
{
	int	(*d_open)();
	int	(*d_close)();
	int	(*d_read)();
	int	(*d_write)();
	int	(*d_sgtty)();
} cdevsw[];

int	bdevcnt;
int	cdevcnt;




































Jun 19 11:25 1978  file.h Page 1


/*
 * One file structure is allocated for each open/creat/pipe call.
 * Main use is to hold the read/write pointer associated with each
 * open file.
 */
struct	file
{
	char	f_flag;
	char	f_count;	/* reference count */
	struct inode *f_inode;	/* pointer to inode structure */
	char	*f_offset[2];	/* read/write character pointer */
};

extern struct file file[];

/* flags */
#define	FREAD	01
#define	FWRITE	02
#define	FPIPE	04












































Jun 19 11:25 1978  filsys.h Page 1


/*
 * Definition of the unix super block.
 * The root super block is allocated and
 * read in iinit/alloc.c. Subsequently
 * a super block is allocated and read
 * with each mount (smount/sys3.c) and
 * released with unmount (sumount/sys3.c).
 * A disk block is ripped off for storage.
 * See alloc.c for general alloc/free
 * routines for free list and I list.
 */
struct	filsys
{
	char	*s_isize;	/* size in blocks of I list */
	char	*s_fsize;	/* size in blocks of entire volume */
	int	s_nfree;	/* number of in core free blocks (0-100) */
	int	s_free[100];	/* in core free blocks */
	int	s_ninode;	/* number of in core I nodes (0-100) */
	int	s_inode[100];	/* in core free I nodes */
	char	s_flock;	/* lock during free list manipulation */
	char	s_ilock;	/* lock during I list manipulation */
	char	s_fmod;		/* super block modified flag */
	char	s_ronly;	/* mounted read-only flag */
	long	s_time;		/* current date of last update */
	int	pad[40];
	int	s_tfree;	/* Total free, for subsystem examination */
	int	s_tinode;	/* Free inodes, for subsystem examination */
	char	s_fname[6];	/* File system name */
	char	s_fpack[6];	/* File system pack name */
};

































Jun 19 11:25 1978  ino.h Page 1


/*
 * Inode structure as it appears on
 * the disk. Not used by the system,
 * but by things like check, df, dump.
 */
struct	inode
{
	int	i_mode;
	char	i_nlink;
	char	i_uid;
	char	i_gid;
	char	i_size0;
	char	*i_size1;
	int	i_addr[8];
	int	i_atime[2];
	int	i_mtime[2];
};

/* modes */
#define	IALLOC	0100000
#define	IFMT	060000
#define		IFDIR	040000
#define		IFCHR	020000
#define		IFBLK	060000
#define	ILARG	010000
#define	ISUID	04000
#define	ISGID	02000
#define ISVTX	01000
#define	IREAD	0400
#define	IWRITE	0200
#define	IEXEC	0100
































Jun 19 11:25 1978  inode.h Page 1


/*
 * The I node is the focus of all
 * file activity in unix. There is a unique
 * inode allocated for each active file,
 * each current directory, each mounted-on
 * file, text file, and the root. An inode is 'named'
 * by its dev/inumber pair. (iget/iget.c)
 * Data, from mode on, is read in
 * from permanent inode on volume.
 */
struct	inode
{
	char	i_flag;
	char	i_count;	/* reference count */
	int	i_dev;		/* device where inode resides */
	int	i_number;	/* i number, 1-to-1 with device address */
	int	i_mode;
	char	i_nlink;	/* directory entries */
	char	i_uid;		/* owner */
	char	i_gid;		/* group of owner */
	char	i_size0;	/* most significant of size */
	char	*i_size1;	/* least sig */
	int	i_addr[8];	/* device addresses constituting file */
	int	i_lastr;	/* last logical block read (for read-ahead) */
};

extern struct inode inode[];

/* flags */
#define	ILOCK	01		/* inode is locked */
#define	IUPD	02		/* inode has been modified */
#define	IACC	04		/* inode access time to be updated */
#define	IMOUNT	010		/* inode is mounted on */
#define	IWANT	020		/* some process waiting on lock */
#define	ITEXT	040		/* inode is pure text prototype */

/* modes */
#define	IALLOC	0100000		/* file is used */
#define	IFMT	060000		/* type of file */
#define		IFDIR	040000	/* directory */
#define		IFCHR	020000	/* character special */
#define		IFBLK	060000	/* block special, 0 is regular */
#define	ILARG	010000		/* large addressing algorithm */
#define	ISUID	04000		/* set user id on execution */
#define	ISGID	02000		/* set group id on execution */
#define ISVTX	01000		/* save swapped text even after use */
#define	IREAD	0400		/* read, write, execute permissions */
#define	IWRITE	0200
#define	IEXEC	0100














Jun 19 11:26 1978  io.h Page 1


#ifdef DQS11B_0
#define DQS11
#endif
#ifdef DQS11A_0
#define DQS11
#endif
#include "../hd/tty.h"
#include "../hd/peri.h"

#ifdef RP03_0
struct {
	char *nblocks;
	int	cyloff;
} rp_sizes[8] {
	7600,	0,		/* cyl 0 thru 37 */
	36200,	38,		/* cyl 38 thru 218 */
	36200,	219,		/* cyl 219 thru 399 */
	65535,	40,		/* cyl 40 thru 367 */
	36200,	22,		/* cyl 22 thru 202 */
	40600,	203,		/* cyl 203 thru 405 */
	0,	0,
	0,	0,
};
#endif
#ifdef RP05_0
#define RP04_0
#endif
#ifdef RP04_0
struct {
	char *nblocks;
	int	cyloff;
} hp_sizes[8] {
	11286,	0,		/* cyl 0 thru 26 */
	53504,	27,		/* cyl 27 thru 154 */
	53504,	155,		/* cyl 155 thru 282 */
	53504,	283,		/* cyl 283 thru 410 */
	65535,	27,		/* cyl 27 thru 183 */
	65535,	184,		/* cyl 184 thru 340 */
	29260,	341,		/* cyl 341 thru 410 */
	0,	0,
};
#endif
#ifdef RP06_0
struct {
	char *nblocks;
	int	cyloff;
} hp_sizes[8] {
	11286,	0,		/* cyl 0 thru 26 */
	65535,	27,		/* cyl 27 thru 183 */
	53504,	155,		/* cyl 155 thru 282 */
	53504,	283,		/* cyl 282 thru 410 */
	65535,	184,		/* cyl 184 thru 340 */
	65535,	341,		/* cyl 341 thru 497 */
	65535,	498,		/* cyl 498 thru 654 */
	65535,	655,		/* cyl 655 thru 811 */
};







Jun 19 11:26 1978  io.h Page 2


#endif

#ifdef DQS11
struct dqsdat dqsx[] {
#ifdef DQS11B_0
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_0
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_1
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_1
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_2
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_2
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
#ifdef DQS11B_3
	{ 0,0,0,0,0,026402,070020,064420,0150440,067,055,075,046,03 },
#endif
#ifdef DQS11A_3
	{ 0,0,0,0,2,0102402,0130020,035420,0160440,04,0205,025,0227,0203 },
#endif
};
#endif

































Jun 19 11:26 1978  param.h Page 1


/*
 * fundamental variables
 * don't change too often
 */

#define	NOFILE	15		/* max open files per process */
#define	SSIZE	12		/* initial stack size (*64 bytes) */
#define	SINCR	12		/* increment of stack (*64 bytes) */
#define	NCARGS	4096
#define	HZ	60		/* Ticks/second of the clock */
#define	NSWB	3		/* size of swap pool */
#define	CANBSIZ	256		/* max size of typewriter line */
#define	MAXMEM	(64*32)		/* max core per process - first # is Kw */
#define	USIZE	12		/* size of user block (*64) */
/*
 * priorities
 * probably should not be
 * altered too much
 */

#define	PSWP	-100
#define	PINOD	-90
#define	PRIBIO	-50
#define	PPIPE	1
#define	PWAIT	40
#define	PSLEP	90
#define	PUSER	100

/*
 * signals
 * dont change
 */

#define	NSIG	16
/*
 * No more than 16 signals (1-16) because they are
 * stored in bits in a word.
 */
#define	SIGHUP	1	/* hangup */
#define	SIGINT	2	/* interrupt (rubout) */
#define	SIGQIT	3	/* quit (FS) */
#define	SIGINS	4	/* illegal instruction */
#define	SIGTRC	5	/* trace or breakpoint */
#define	SIGIOT	6	/* iot */
#define	SIGEMT	7	/* emt */
#define	SIGFPT	8	/* floating exception */
#define	SIGKIL	9	/* kill, uncatchable termination */
#define	SIGBUS	10	/* bus error */
#define	SIGSEG	11	/* segmentation violation */
#define	SIGSYS	12	/* bad system call */
#define	SIGPIPE	13	/* end of pipe */
#define	SIGCLK	14	/* alarm clock */
#define	SIGTRM	15	/* Catchable termination */

/*
 * fundamental constants







Jun 19 11:26 1978  param.h Page 2


 * cannot be changed
 */

#define	NULL	0
#define	NODEV	(-1)
#define	ROOTINO	1		/* i number of all roots */
#define	DIRSIZ	14		/* max characters per directory */

/*
 * structure to access an
 * integer in bytes
 */
struct
{
	char	lobyte;
	char	hibyte;
};

/*
 * structure to access an integer
 */
struct
{
	int	integ;
};

/*
 * structure to access a long as integers
 */
struct {
	int	hiword;
	int	loword;
};

/*
 * Certain processor registers
 */
#define PS	0177776
#define KL	0177560
#define SW	0177570

/*
 * Some macros for units conversion
 */
/* Core clicks (64 bytes) to segments */
#define	ctos(x)	((x+127)>>7)

/* Core clicks (64 bytes) to blocks */
#define	ctob(x)	((x+7)>>3)

/* major part of a device */
#define major(x)	(int)((x.hibyte)&0377)

/* minor part of a device */
#define minor(x)	(int)(x&0377)








Jun 19 11:26 1978  peri.h Page 1


struct vp {
	int	vp_state;
	char	*vp_buf;
	char	*vp_count;
	int	vp_offset;
};
extern struct vp vp_vp[];

struct du {
	char	*du_buf;
	char	*du_bufp;
	int	du_nxmit;
	char	du_state;
	char	du_dummy;
	int	du_proc;
	char	*du_bufb;
	char	*du_bufe;
	int	du_nleft;
};
extern struct du du_du[];

#ifdef DQS11
#define NDQ 4
#define NBF 2

struct dqsbuf	{
	int bufl,bufc;
	char *bufb;
	struct dqsbuf *bufn;
	struct buf *bufa;
};

struct dqsdat	{
	int  state;
	char qcase,open;
	char *addr;
	int  dly;
	int  ttd,ack0,wack,ackx;
	char eot,enq,nak,etb,etx;
	char slp,time,try;
	int  cc,resp,uoff;
	struct dqsbuf *x,*q,*u;
	struct dqsbuf bf[NBF];
};

struct dqsdat dqsx[];
#endif
















Jun 19 11:26 1978  proc.h Page 1


/*
 * One structure allocated per active process. It contains all data needed
 * about the process while the process may be swapped out.
 * Other per process data (user.h) is swapped with the process.
 */
struct	proc {
	char	p_stat;
	char	p_flag;
	char	p_pri;		/* priority, negative is high */
	char	p_time;		/* resident time for scheduling */
	char	p_cpu;		/* cpu usage for scheduling */
	char	p_nice;		/* nice for cpu usage */
	int	p_sig;		/* signals pending to this process */
	int	p_uid;		/* user id, used to direct tty signals */
	int	p_pgrp;		/* name of process group leader */
	int	p_pid;		/* unique process id */
	int	p_ppid;		/* process id of parent */
	int	p_addr;		/* address of swappable image */
	int	p_size;		/* size of swappable image (*64 bytes) */
	int	p_wchan;	/* event process is awaiting */
	int	*p_textp;	/* pointer to text structure */
	int	*p_link;	/* linked list of running processes */
	int	p_clktim;	/* time to alarm clock signal */
};
extern struct proc proc[];

/* stat codes */
#define	SSLEEP	1		/* awaiting an event */
#define	SWAIT	2		/* (abandoned state) */
#define	SRUN	3		/* running */
#define	SIDL	4		/* intermediate state in process creation */
#define	SZOMB	5		/* intermediate state in process termination */
#define	SSTOP	6		/* process being traced */

/* flag codes */
#define	SLOAD	01		/* in core */
#define	SSYS	02		/* scheduling process */
#define	SLOCK	04		/* process cannot be swapped */
#define	SSWAP	010		/* process is being swapped out */
#define	STRC	020		/* process is being traced */
#define	SWTED	040		/* another tracing flag */

/*
 * Structure used to access saved times and status
 * of a dead processs, by the parent.
 * Overlays the proc structure.
 */
struct	xproc {
	char	p_stat;
	char	p_flag;
	char	p_pri;		/* priority, negative is high */
	char	p_time;		/* resident time for scheduling */
	char	p_cpu;		/* cpu usage for scheduling */
	char	p_nice;		/* nice for cpu usage */
	int	p_sig;		/* signals pending to this process */
	int	p_uid;		/* user id, used to direct tty signals */







Jun 19 11:26 1978  proc.h Page 2


	int	p_pgrp;		/* name of process group leader */
	int	p_pid;		/* unique process id */
	int	p_ppid;		/* process id of parent */
	int	xp_xstat;	/* Exit status for wait */
	long	xp_utime;	/* user time, this proc */
	long	xp_stime;	/* system time, this proc */
	int	p_clktim;	/* time to alarm clock signal */
};























































Jun 19 11:26 1978  reg.h Page 1


/*
 * Location of the users' stored registers relative to R0.
 * Usage is u.u_ar0[XX].
 */
#define	R0	(0)
#define	R1	(-2)
#define	R2	(-9)
#define	R3	(-8)
#define	R4	(-7)
#define	R5	(-6)
#define	R6	(-3)
#define	R7	(1)
#define	RPS	(2)

#define	TBIT	020		/* PS trace bit */
















































Jun 19 11:26 1978  seg.h Page 1


/*
 * KT-11 addresses and bits.
 */

#define	UISD	0177600		/* first user I-space descriptor register */
#define	UISA	0177640		/* first user I-space address register */
#define	UDSA	0177660		/* first user D-space address register */
#define	RO	02		/* access abilities */
#define	RW	06
#define	ED	010		/* extend direction */
#define	TX	020		/* Software: text segment */

/*
 * structure used to address a sequence of integers.
 */
struct
{
	int	r[];
};
int	*ka6;		/* 11/40 KISA6; 11/45 KDSA6 */

/*
 * address to access 11/70 UNIBUS map
 */
#define	UBMAP	0170200






































Jun 19 11:26 1978  space.h Page 1


#include "../hd/buf.h"
struct	buf	buf[NBUF];	/* buffer headers */
struct	buf	bfreelist;	/* head of the free list of buffers */
char	buffers[NBUF][514];	/* buffer pool */

#include "../hd/file.h"
struct	file	file[NFILE];	/* file table */

#include "../hd/inode.h"
struct	inode	inode[NINODE];	/* inode table */

#include "../hd/proc.h"
struct	proc	proc[NPROC];	/* process table */

#include "../hd/text.h"
struct	text text[NTEXT];	/* text table */

#include "../hd/systm.h"
struct map coremap[CMAPSIZ];
struct map swapmap[SMAPSIZ];
struct callo callout[NCALL];
struct mount mount[NMOUNT];

struct	cblock	cfree[NCLIST];

#include "../hd/var.h"
struct var v {
	NBUF,
	NCALL,
	NINODE,
	&inode[NINODE],
	NFILE,
	&file[NFILE],
	NMOUNT,
	&mount[NMOUNT],
	NPROC,
	&proc[1],
	NTEXT,
	&text[NTEXT],
	NCLIST,
};

char	pwbname[9] "pwbname";




















Jun 19 11:26 1978  systm.h Page 1


/*
 * Random set of variables used by more than one routine.
 */
struct map {
	int	m_size;
	char	*m_addr;
};
struct map coremap[];	/* core allocation map */
struct map swapmap[];	/* swap allocation map */
int	*rootdir;		/* pointer to inode of root directory */
int	*runq;			/* head of linked list of running processes */
int	cputype;		/* type of cpu =40, 45, or 70 */
int	lbolt;			/* time of day in 60th not in time */
long	time;			/* time in sec from 1970 */
long	tout;			/* time of day of next sleep */
/*
 * The callout structure is for a routine arranging to be
 *  called by the clock interrupt (clock.c) with a specified argument,
 * in a specified amount of time.
 * Used, for example, to time tab delays on typewriters.
 */
struct	callo
{
	int	c_time;		/* incremental time */
	int	c_arg;		/* argument to routine */
	int	(*c_func)();	/* routine */
} callout[];
/*
 * Mount structure.
 * One allocated on every mount.
 * Used to find the super block.
 */
struct	mount
{
	int	m_dev;		/* device mounted */
	int	*m_bufp;	/* pointer to superblock */
	int	*m_inodp;	/* pointer to mounted on inode */
} mount[];

int	mpid;			/* generic for unique process id's */
char	runin;			/* scheduling flag */
char	runout;			/* scheduling flag */
char	runrun;			/* scheduling flag */
char	curpri;			/* more scheduling */
int	maxmem;			/* actual max memory per process */
int	*lks;			/* pointer to clock device */
int	rootdev;		/* dev of root see conf.c */
int	swapdev;		/* dev of swap see conf.c */
int	swplo;			/* block number of swap space */
int	nswap;			/* size of swap space */
int	updlock;		/* lock for sync */
int	rablock;		/* block to be read ahead */
char	regloc[];		/* locs. of saved user registers (trap.c) */
char	pwbname[];









Jun 19 11:26 1978  text.h Page 1


/*
 * Text structure.
 * One allocated per pure procedure on swap device.
 * Manipulated by text.c
 */
struct text
{
	int	x_daddr;	/* disk address of segment */
	int	x_caddr;	/* core address, if loaded */
	int	x_size;		/* size (*64) */
	int	*x_iptr;	/* inode of prototype */
	char	x_count;	/* reference count */
	char	x_ccount;	/* number of loaded references */
	char	x_flag;		/* traced, written flags */
};

extern struct text text[];

#define	XWRIT	02		/* Text written into, must swap out */
#define	XLOAD	04		/* Currently being read from file */
#define	XLOCK	010		/* Being swapped in or out */
#define	XWANT	020		/* Wanted for swapping */









































Jun 19 11:26 1978  tty.h Page 1


/*
 * A clist structure is the head of a linked list queue of characters.
 * The characters are stored in 4-word
 * blocks containing a link and 6 characters.
 * The routines getc and putc (m45.s or m40.s)
 * manipulate these structures.
 */
struct clist
{
	int	c_cc;		/* character count */
	int	c_cf;		/* pointer to first block */
	int	c_cl;		/* pointer to last block */
};

/*
 * A tty structure is needed for each UNIX character device that
 * is used for normal terminal IO.
 * The routines in tty.c handle the common code associated with
 * these structures.
 * The definition and device dependent code is in each driver.
 */
struct tty
{
	struct	clist t_rawq;	/* input chars right off device */
	struct	clist t_canq;	/* input chars after erase and kill */
	struct	clist t_outq;	/* output list to device */
	int	t_flags;	/* mode, settable by stty call */
	int	*t_addr;	/* device address (register or startup fcn) */
	char	t_delct;	/* number of delimiters in raw q */
	char	t_col;		/* printing column of device */
	char	t_erase;	/* erase character */
	char	t_kill;		/* kill character */
	char	t_state;	/* internal state, not visible externally */
	char	t_char;		/* character temporary */
	int	t_speeds;	/* output+input line speed */
	int	t_pgrp;		/* process group name */
};

/*
 * The actual structure of a clist block manipulated by
 * getc and putc (mch.s)
 */
struct cblock {
	struct cblock *c_next;
	char info[6];
};

struct ttydma {
	char	c[8];
};

#define	TTIPRI	10
#define	TTOPRI	20

#define	CERASE	'#'		/* default special characters */
#define	CEOT	004







Jun 19 11:26 1978  tty.h Page 2


#define	CKILL	'@'
#define	CQUIT	034		/* FS, cntl shift L */
#define	CINTR	0177		/* DEL */

/* limits */
#define	TTHIWAT	100
#define	TTLOWAT	50
#define	TTYHOG	256

/* modes */
#define	HUPCL	01
#define	XTABS	02
#define	LCASE	04
#define	ECHO	010
#define	CRMOD	020
#define	RAW	040
#define	ODDP	0100
#define	EVENP	0200
#define	NLDELAY	001400
#define	TBDELAY	006000
#define	CRDELAY	030000
#define	VTDELAY	040000

/* Hardware bits */
#define	DONE	0200
#define	IENABLE	0100

/* Internal state bits */
#define	TIMEOUT	01		/* Delay timeout in progress */
#define	WOPEN	02		/* Waiting for open to complete */
#define	ISOPEN	04		/* Device is open */
#define	SSTART	010		/* Has special start routine at addr */
#define	CARR_ON	020		/* Software copy of carrier-present */
#define	BUSY	040		/* Output in progress */
#define	ASLEEP	0100		/* Wakeup when output done */




























Jun 19 11:26 1978  user.h Page 1


/*
 * The user structure.
 * One allocated per process.
 * Contains all per process data that doesn't need to be referenced
 * while the process is swapped.
 * The user block is USIZE*64 bytes long; resides at virtual kernel
 * loc 140000; contains the system stack per user; is cross referenced
 * with the proc structure for the same process.
 */
struct user
{
	int	u_rsav[2];		/* save r5,r6 when exchanging stacks */
	int	u_fsav[25];		/* save fp registers */
					/* rsav and fsav must be first in structure */
	char	u_segflg;		/* IO flag: 0:user D; 1:system; 2:user I */
	char	u_error;		/* return error code */
	char	u_uid;			/* effective user id */
	char	u_gid;			/* effective group id */
	char	u_ruid;			/* real user id */
	char	u_rgid;			/* real group id */
	int	u_procp;		/* pointer to proc structure */
	char	*u_base;		/* base address for IO */
	char	*u_count;		/* bytes remaining for IO */
	char	*u_offset[2];		/* offset in file for IO */
	int	*u_cdir;		/* pointer to inode of current directory */
	char	u_dbuf[DIRSIZ];		/* current pathname component */
	char	*u_dirp;		/* current pointer to inode */
	struct	{			/* current directory entry */
		int	u_ino;
		char	u_name[DIRSIZ];
	} u_dent;
	int	*u_pdir;		/* inode of parent directory of dirp */
	int	u_uisa[16];		/* prototype of segmentation addresses */
	int	u_uisd[16];		/* prototype of segmentation descriptors */
	int	u_ofile[NOFILE];	/* pointers to file structures of open files */
	int	u_arg[5];		/* arguments to current system call */
	int	u_tsize;		/* text size (*64) */
	int	u_dsize;		/* data size (*64) */
	int	u_ssize;		/* stack size (*64) */
	int	u_sep;			/* flag for I and D separation */
	int	u_qsav[2];		/* label variable for quits and interrupts */
	int	u_ssav[2];		/* label variable for swapping */
	int	u_signal[NSIG];		/* disposition of signals */
	long	u_utime;		/* this process user time */
	long	u_stime;		/* this process system time */
	long	u_cutime;		/* sum of childs' utimes */
	long	u_cstime;		/* sum of childs' stimes */
	int	*u_ar0;			/* address of users saved R0 */
	int	u_prof[4];		/* profile arguments */
	char	u_intflg;		/* catch intr from sys */
	int	u_ttyp;			/* controlling tty pointer */
	int	u_ttyd;			/* controlling tty dev */
	struct {			/* header of executable file */
		int	ux_mag;		/* magic number */
		int	ux_tsize;	/* text size */
		int	ux_dsize;	/* data size */







Jun 19 11:26 1978  user.h Page 2


		int	ux_bsize;	/* bss size */
		int	ux_ssize;	/* symbol table size */
		int	ux_entloc;	/* entry location */
	} u_exdata;
	int	u_udata[16];		/* user log data */
					/* kernel stack per user
					 * extends from u + USIZE*64
					 * backward not to reach here
					 */
};
extern u;

/* u_error codes */
#define	EPERM	1
#define	ENOENT	2
#define	ESRCH	3
#define	EINTR	4
#define	EIO	5
#define	ENXIO	6
#define	E2BIG	7
#define	ENOEXEC	8
#define	EBADF	9
#define	ECHILD	10
#define	EAGAIN	11
#define	ENOMEM	12
#define	EACCES	13
#define	EFAULT	14
#define	ENOTBLK	15
#define	EBUSY	16
#define	EEXIST	17
#define	EXDEV	18
#define	ENODEV	19
#define	ENOTDIR	20
#define	EISDIR	21
#define	EINVAL	22
#define	ENFILE	23
#define	EMFILE	24
#define	ENOTTY	25
#define	ETXTBSY	26
#define	EFBIG	27
#define	ENOSPC	28
#define	ESPIPE	29
#define	EROFS	30
#define	EMLINK	31
#define	EPIPE	32


















Jun 19 11:26 1978  var.h Page 1


struct var {
	int	v_buf;
	int	v_call;
	int	v_inode;
	char *	ve_inode;
	int	v_file;
	char *	ve_file;
	int	v_mount;
	char *	ve_mount;
	int	v_proc;
	char *	ve_proc;
	int	v_text;
	char *	ve_text;
	int	v_clist;
};
extern struct var v;















































Jun 19 11:26 1978  alloc.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/filsys.h"
#include "../hd/conf.h"
#include "../hd/buf.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/var.h"

/*
 * iinit is called once (from main) very early in initialization.
 * It reads the root's super block and initializes the current date
 * from the last modified date.
 *
 * panic: iinit -- cannot read the super block, usually because of an IO error.
 */
iinit()
{
	register *cp, *bp;

	(*bdevsw[major(rootdev)].d_open)(minor(rootdev), 1);
	bp = bread(rootdev, 1);
	cp = getblk(NODEV);
	if(u.u_error)
		panic("iinit");
	bcopy(bp->b_addr, cp->b_addr, 256);
	brelse(bp);
	mount[0].m_bufp = cp;
	mount[0].m_dev = rootdev;
	cp = cp->b_addr;
	cp->s_flock = 0;
	cp->s_ilock = 0;
	cp->s_ronly = 0;
	cp->s_ninode = 0;	/* zero free inode cnt to force init by ialloc */
	time = cp->s_time;
}

/*
 * alloc will obtain the next available free disk block from the free list
 * of the specified device.
 * The super block has up to 100 remembered free blocks;
 * the last of these is read to obtain 100 more . . .
 *
 * no space on dev x/y -- when the free list is exhausted.
 */
alloc(dev)
{
	int bno;
	register *bp, *ip, *fp;

	fp = getfs(dev);
	while(fp->s_flock)
		sleep(&fp->s_flock, PINOD);
	do {
		if(fp->s_nfree <= 0)







Jun 19 11:26 1978  alloc.c Page 2


			goto nospace;
		bno = fp->s_free[--fp->s_nfree];
		if(bno == 0)
			goto nospace;
	} while (badblock(fp, bno, dev));
	if(fp->s_nfree <= 0) {
		fp->s_flock++;
		bp = bread(dev, bno);
		ip = bp->b_addr;
		fp->s_nfree = *ip++;
		bcopy(ip, fp->s_free, 100);
		brelse(bp);
		fp->s_flock = 0;
		wakeup(&fp->s_flock);
	}
	bp = getblk(dev, bno);
	clrbuf(bp);
	if(fp->s_tfree) fp->s_tfree--;
	fp->s_fmod = 1;
	return(bp);

nospace:
	fp->s_nfree = 0;
	fp->s_tfree = 0;
	prdev("no space", dev);
	u.u_error = ENOSPC;
	return(NULL);
}

/*
 * place the specified disk block back on the free list of the
 * specified device.
 */
free(dev, bno)
{
	register *fp, *bp, *ip;

	fp = getfs(dev);
	fp->s_fmod = 1;
	while(fp->s_flock)
		sleep(&fp->s_flock, PINOD);
	if (badblock(fp, bno, dev))
		return;
	if(fp->s_nfree <= 0) {
		fp->s_nfree = 1;
		fp->s_free[0] = 0;
	}
	if(fp->s_nfree >= 100) {
		fp->s_flock++;
		bp = getblk(dev, bno);
		ip = bp->b_addr;
		*ip++ = fp->s_nfree;
		bcopy(fp->s_free, ip, 100);
		fp->s_nfree = 0;
		bwrite(bp);
		fp->s_flock = 0;







Jun 19 11:26 1978  alloc.c Page 3


		wakeup(&fp->s_flock);
	}
	fp->s_free[fp->s_nfree++] = bno;
	fp->s_tfree++;
	fp->s_fmod = 1;
}

/*
 * Check that a block number is in the range between the I list
 * and the size of the device.
 * This is used mainly to check that a
 * garbage file system has not been mounted.
 *
 * bad block on dev x/y -- not in range
 */
badblock(afp, abn, dev)
{
	register struct filsys *fp;
	register char *bn;

	fp = afp;
	bn = abn;
	if (bn < fp->s_isize+2 || bn >= fp->s_fsize) {
		prdev("bad block", dev);
		return(1);
	}
	return(0);
}

/*
 * Allocate an unused I node on the specified device.
 * Used with file creation.
 * The algorithm keeps up to 100 spare I nodes in the
 * super block. When this runs out, a linear search through the
 * I list is instituted to pick up 100 more.
 */
ialloc(dev)
{
	register *fp, *bp, *ip;
	int i, j, k, ino;

	fp = getfs(dev);
	while(fp->s_ilock)
		sleep(&fp->s_ilock, PINOD);
loop:
	if(fp->s_ninode > 0) {
		ino = fp->s_inode[--fp->s_ninode];
		ip = iget(dev, ino);
		if (ip==NULL)
			return(NULL);
		if(ip->i_mode == 0) {
			for(bp = &ip->i_mode; bp < &ip->i_addr[8];)
				*bp++ = 0;
			if(fp->s_tinode) fp->s_tinode--;
			fp->s_fmod = 1;
			return(ip);







Jun 19 11:26 1978  alloc.c Page 4


		}
		/*
		 * Inode was allocated after all.
		 * Look some more.
		 */
		iput(ip);
		goto loop;
	}
	fp->s_ilock++;
	ino = 0;
	for(i=0; i<fp->s_isize; i++) {
		bp = bread(dev, i+2);
		ip = bp->b_addr;
		for(j=0; j<256; j=+16) {
			ino++;
			if(ip[j] != 0)
				continue;
			for(k=0; k<v.v_inode; k++)
			if(dev==inode[k].i_dev && ino==inode[k].i_number)
				goto cont;
			fp->s_inode[fp->s_ninode++] = ino;
			if(fp->s_ninode >= 100)
				break;
		cont:;
		}
		brelse(bp);
		if(fp->s_ninode >= 100)
			break;
	}
	fp->s_ilock = 0;
	wakeup(&fp->s_ilock);
	if (fp->s_ninode > 0)
		goto loop;
	prdev("Out of inodes", dev);
	u.u_error = ENOSPC;
	fp->s_tinode = 0;
	return(NULL);
}

/*
 * Free the specified I node on the specified device.
 * The algorithm stores up to 100 I nodes in the super
 * block and throws away any more.
 */
ifree(dev, ino)
{
	register *fp;

	fp = getfs(dev);
	fp->s_tinode++;
	if(fp->s_ilock)
		return;
	if(fp->s_ninode >= 100)
		return;
	fp->s_inode[fp->s_ninode++] = ino;
	fp->s_fmod = 1;







Jun 19 11:26 1978  alloc.c Page 5


}

/*
 * getfs maps a device number into a pointer to the incore super block.
 * The algorithm is a linear search through the mount table.
 * A consistency check of the in core free-block and i-node counts.
 *
 * bad count on dev x/y -- the count
 *	check failed. At this point, all
 *	the counts are zeroed which will
 *	almost certainly lead to "no space"
 *	diagnostic
 * panic: no fs -- the device is not mounted.
 *	this "cannot happen"
 */
getfs(dev)
{
	register struct mount *p;
	register char *n1, *n2;

	for (p = &mount[0]; p < v.ve_mount; p++)
	if(p->m_bufp != NULL && p->m_dev == dev) {
		p = p->m_bufp->b_addr;
		n1 = p->s_nfree;
		n2 = p->s_ninode;
		if(n1 > 100 || n2 > 100) {
			prdev("bad count", dev);
			p->s_nfree = 0;
			p->s_ninode = 0;
		}
		return(p);
	}
	panic("no fs");
}

/*
 * update is the internal name of 'sync'. It goes through the disk
 * queues to initiate sandbagged IO; goes through the I nodes to write
 * modified nodes; and it goes through the mount table to initiate modified
 * super blocks.
 */
update()
{
	register struct inode *ip;
	register struct mount *mp;
	register *bp;

	if(updlock)
		return;
	updlock++;
	for (mp = &mount[0]; mp < v.ve_mount; mp++)
		if(mp->m_bufp != NULL) {
			ip = mp->m_bufp->b_addr;
			if(ip->s_fmod==0 || ip->s_ilock!=0 ||
			   ip->s_flock!=0 || ip->s_ronly!=0)
				continue;







Jun 19 11:26 1978  alloc.c Page 6


			bp = getblk(mp->m_dev, 1);
			ip->s_fmod = 0;
			ip->s_time = time;
			bcopy(ip, bp->b_addr, 256);
			bwrite(bp);
		}
	for (ip = &inode[0]; ip < v.ve_inode; ip++)
		if((ip->i_flag&ILOCK)==0 && ip->i_count) {
			ip->i_flag =| ILOCK;
			ip->i_count++;
			iupdat(ip);
			iput(ip);
		}
	updlock = 0;
	bflush(NODEV);
}















































Jun 19 11:27 1978  clock.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/var.h"

int	sstime;
int	rrcput[256];

#define	UMODE	0170000
#define	SCHMAG	8/10

/*
 * clock is called straight from
 * the real time clock interrupt.
 *
 * Functions:
 *	reprime clock
 *	copy *switches to display
 *	implement callouts
 *	maintain user/system times
 *	maintain date
 *	profile
 *	tout wakeup (sys sleep)
 *	lightning bolt wakeup (every 4 sec)
 *	alarm clock signals
 *	jab the scheduler
 */
clock(dev, sp, r1, nps, r0, pc, ps)
{
	register struct callo *p1, *p2;
	register struct proc *pp;
	int a;

	/*
	 * restart clock
	 */

	*lks = 0115;

	/*
	 * display register
	 */

	display();

	/*
	 * callouts
	 * if none, just return
	 * else update first non-zero time
	 */

	if(callout[0].c_func == 0)
		goto out;
	p2 = &callout[0];







Jun 19 11:27 1978  clock.c Page 2


	while(p2->c_time<=0 && p2->c_func!=0)
		p2++;
	p2->c_time--;

	/*
	 * if ps is high, just return
	 */

	if((ps&0340) != 0)
		goto out;

	/*
	 * callout
	 */

	spl5();
	if(callout[0].c_time <= 0) {
		p1 = &callout[0];
		while(p1->c_func != 0 && p1->c_time <= 0) {
			(*p1->c_func)(p1->c_arg);
			p1++;
		}
		p2 = &callout[0];
		while(p2->c_func = p1->c_func) {
			p2->c_time = p1->c_time;
			p2->c_arg = p1->c_arg;
			p1++;
			p2++;
		}
	}

	/*
	 * lightning bolt time-out
	 * and time of day
	 */

out:
	sstime++;
	rrcput[u.u_ruid&0377]++;
	if((ps&UMODE) == UMODE) {
		u.u_utime++;
		if(u.u_prof[3])
			incupc(pc, u.u_prof);
	} else
		u.u_stime++;
	pp = u.u_procp;
	if(++pp->p_cpu == 0)
		pp->p_cpu--;
	if(++lbolt >= HZ) {
		if((ps&0340) != 0)
			return;
		lbolt =- HZ;
		++time;
		spl1();
		if (time == tout)
			wakeup(&tout);







Jun 19 11:27 1978  clock.c Page 3


		runrun++;
		if((time.loword&01) == 0)
			wakeup(&lbolt);
		for(pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_stat) {
			if(pp->p_time != 127)
				pp->p_time++;
			if(pp->p_clktim)
				if(--pp->p_clktim == 0)
					psignal(pp, SIGCLK);
			pp->p_cpu =>> 1;
			if(pp->p_pri >= PUSER)
				setpri(pp);
		}
		if(runin!=0) {
			runin = 0;
			setrun(&proc[0]);
		}
		if((ps&UMODE) == UMODE) {
			u.u_ar0 = &r0;
			if(issig())
				psig();
			setpri(u.u_procp);
		}
	}
}

/*
 * timeout is called to arrange that fun(arg) is called in tim/HZ seconds.
 * An entry is sorted into the callout structure.
 * The time in each structure entry is the number of HZ's more
 * than the previous entry. In this way, decrementing the
 * first entry has the effect of updating all entries.
 *
 * The panic is there because there is nothing
 * intelligent to be done if an entry won't fit.
 */
timeout(fun, arg, tim)
{
	register struct callo *p1, *p2;
	register t;
	int s;

	t = tim;
	s = PS->integ;
	p1 = &callout[0];
	spl7();
	while(p1->c_func != 0 && p1->c_time <= t) {
		t =- p1->c_time;
		p1++;
	}
	if (p1 >= &callout[v.v_call-1])
		panic("Timeout table overflow");
	p1->c_time =- t;
	p2 = p1;
	while(p2->c_func != 0)







Jun 19 11:27 1978  clock.c Page 4


		p2++;
	while(p2 >= p1) {
		(p2+1)->c_time = p2->c_time;
		(p2+1)->c_func = p2->c_func;
		(p2+1)->c_arg = p2->c_arg;
		p2--;
	}
	p1->c_time = t;
	p1->c_func = fun;
	p1->c_arg = arg;
	PS->integ = s;
}



















































Jun 19 11:27 1978  fio.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/filsys.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/systm.h"
#include "../hd/var.h"

/*
 * Convert a user supplied file descriptor into a pointer
 * to a file structure.
 * Only task is to check range of the descriptor.
 */
getf(f)
{
	register *fp, rf;

	rf = f;
	if (0<=rf && rf<NOFILE) {
		fp = u.u_ofile[rf];
		if(fp != NULL)
			return(fp);
	}
	u.u_error = EBADF;
	return(NULL);
}

/*
 * Internal form of close.
 * Decrement reference count on file structure.
 * Also make sure the pipe protocol does not constipate.
 *
 * Decrement reference count on the inode following
 * removal to the referencing file structure.
 * On the last close switch out the the device handler for
 * special files.  Note that the handler is called
 * on every open but only the last close.
 */
closef(fp)
int *fp;
{
	register *ip;
	register struct file *rfp;
	int flag;
	register int (*cfunc)();

	if ((rfp = fp) == NULL)
		return;
	ip = rfp->f_inode;
	if (rfp->f_count > 1) {
		rfp->f_count--;
		return;
	}







Jun 19 11:27 1978  fio.c Page 2


	plock(ip);
	flag = rfp->f_flag&FWRITE;
	rfp->f_count = 0;
	if(rfp->f_flag&FPIPE) {
		ip->i_mode =& ~(IREAD|IWRITE);
		wakeup(ip+1);
		wakeup(ip+2);
	}
	cfunc = 0;
	if ((ip->i_mode&IFMT) == IFCHR)
		cfunc = cdevsw[major(ip->i_addr[0])].d_close;
	else if ((ip->i_mode&IFMT)== IFBLK)
		cfunc = bdevsw[major(ip->i_addr[0])].d_close;
	iput(ip);
	if (cfunc == 0)
		return;
	for (rfp=file; rfp < v.ve_file; rfp++)
		if (rfp->f_count && rfp->f_inode==ip)
			return;
	(*cfunc)(minor(ip->i_addr[0]), flag);
}

/*
 * openi called to allow handler of special files to initialize and
 * validate before actual IO.
 * Called only for open of special files.
 */
openi(ip, rw)
register *ip;
{
	register dev, maj;

	dev = minor(ip->i_addr[0]);
	maj = major(ip->i_addr[0]);
	if ((ip->i_mode&IFMT) == IFCHR)
		if (maj >= cdevcnt)
			u.u_error = ENXIO; else
		{
			if (u.u_ttyp == 0)
				u.u_ttyd = ip->i_addr[0];
			(*cdevsw[maj].d_open)(dev, rw);
		} else
		if (maj >= bdevcnt)
			u.u_error = ENXIO; else
			(*bdevsw[maj].d_open)(dev, rw);
}

/*
 * Check mode permission on inode pointer.
 * Mode is READ, WRITE or EXEC.
 * In the case of WRITE, the read-only status of the file
 * system is checked. Also in WRITE, prototype text
 * segments cannot be written.
 * The mode is shifted to select the owner/group/other fields.
 * The super user is granted all permissions.
 */







Jun 19 11:27 1978  fio.c Page 3


access(aip, mode)
int *aip;
{
	register *ip, m;

	ip = aip;
	m = mode;
	if(m == IWRITE) {
		if(getfs(ip->i_dev)->s_ronly != 0) {
			u.u_error = EROFS;
			return(1);
		}
		if(ip->i_flag & ITEXT) {
			u.u_error = ETXTBSY;
			return(1);
		}
	}
	if(u.u_uid == 0)
		return(0);
	if(u.u_uid != ip->i_uid) {
		m =>> 3;
		if(u.u_gid != ip->i_gid)
			m =>> 3;
	}
	if((ip->i_mode&m) != 0)
		return(0);

bad:
	u.u_error = EACCES;
	return(1);
}

/*
 * Look up a pathname and test if the resultant inode is owned by the
 * current user. If not, try for super-user.
 * If permission is granted, return inode pointer.
 */
owner()
{
	register struct inode *ip;
	extern uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if(u.u_uid == ip->i_uid)
		return(ip);
	if (suser())
		return(ip);
	iput(ip);
	return(NULL);
}

/*
 * Test if the current user is the super user.
 */
suser()







Jun 19 11:27 1978  fio.c Page 4


{

	if(u.u_uid == 0)
		return(1);
	u.u_error = EPERM;
	return(0);
}

/*
 * Allocate a user file descriptor.
 */
ufalloc()
{
	register i;

	for (i=0; i<NOFILE; i++)
		if (u.u_ofile[i] == NULL) {
			u.u_ar0[R0] = i;
			return(i);
		}
	u.u_error = EMFILE;
	return(-1);
}

/*
 * Allocate a user file descriptor and a file structure.
 * Initialize the descriptor to point at the file structure.
 *
 * no file -- if there are no available 	file structures.
 */
falloc()
{
	register struct file *fp;
	register i;

	if ((i = ufalloc()) < 0)
		return(NULL);
	for (fp = &file[0]; fp < v.ve_file; fp++)
		if (fp->f_count==0) {
			u.u_ofile[i] = fp;
			fp->f_count++;
			fp->f_offset[0] = 0;
			fp->f_offset[1] = 0;
			return(fp);
		}
	printf("no file\n");
	u.u_error = ENFILE;
	return(NULL);
}














Jun 19 11:27 1978  iget.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/filsys.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Look up an inode by device,inumber.
 * If it is in core (in the inode structure), honor the locking protocol.
 * If it is not in core, read it in from the specified device.
 * If the inode is mounted on, perform the indicated indirection.
 * In all cases, a pointer to a locked inode structure is returned.
 *
 * printf warning: no inodes -- if the inode structure is full
 * panic: no imt -- if the mounted filesystem is not in the mount table.
 *	"cannot happen"
 */
iget(dev, ino)
{
	register struct inode *p;
	register *ip2;
	int *ip1;
	register struct mount *ip;

loop:
	ip = NULL;
	for(p = &inode[0]; p < v.ve_inode; p++) {
		if(dev==p->i_dev && ino==p->i_number) {
			if((p->i_flag&ILOCK) != 0) {
				p->i_flag =| IWANT;
				sleep(p, PINOD);
				goto loop;
			}
			if((p->i_flag&IMOUNT) != 0) {
				for(ip = &mount[0]; ip < v.ve_mount; ip++)
				if(ip->m_inodp == p) {
					dev = ip->m_dev;
					ino = ROOTINO;
					goto loop;
				}
				panic("no imt");
			}
			p->i_count++;
			p->i_flag =| ILOCK;
			return(p);
		}
		if(ip==NULL && p->i_count==0)
			ip = p;
	}
	if((p=ip) == NULL) {
		printf("Inode table overflow\n");
		u.u_error = ENFILE;
		return(NULL);







Jun 19 11:27 1978  iget.c Page 2


	}
	p->i_dev = dev;
	p->i_number = ino;
	p->i_flag = ILOCK;
	p->i_count++;
	p->i_lastr = -1;
	ip = bread(dev, ldiv(ino+31,16));
	/*
	 * Check I/O errors
	 */
	if (ip->b_flags&B_ERROR) {
		brelse(ip);
		iput(p);
		return(NULL);
	}
	ip1 = ip->b_addr + 32*lrem(ino+31, 16);
	ip2 = &p->i_mode;
	while(ip2 < &p->i_addr[8])
		*ip2++ = *ip1++;
	brelse(ip);
	return(p);
}

/*
 * Decrement reference count of an inode structure.
 * On the last reference, write the inode out and if necessary,
 * truncate and deallocate the file.
 */
iput(p)
struct inode *p;
{
	register *rp;

	rp = p;
	if(rp->i_count == 1) {
		rp->i_flag =| ILOCK;
		if(rp->i_nlink <= 0) {
			itrunc(rp);
			rp->i_mode = 0;
			rp->i_flag =| IUPD;
			ifree(rp->i_dev, rp->i_number);
		}
		iupdat(rp);
		prele(rp);
		rp->i_flag = 0;
		rp->i_number = 0;
	}
	rp->i_count--;
	prele(rp);
}

/*
 * Check accessed and update flags on an inode structure.
 * If either is on, update the inode with the current time.
 */
iupdat(p)







Jun 19 11:27 1978  iget.c Page 3


int *p;
{
	register *ip1, *ip2, *rp;
	int *bp, i;

	rp = p;
	if((rp->i_flag&(IUPD|IACC)) != 0) {
		if(getfs(rp->i_dev)->s_ronly) {
			if(rp->i_flag&IUPD)
				u.u_error = EROFS;
			rp->i_flag =& ~(IUPD|IACC);
			return;
		}
		i = rp->i_number+31;
		bp = bread(rp->i_dev, ldiv(i,16));
		ip1 = bp->b_addr + 32*lrem(i, 16);
		ip2 = &rp->i_mode;
		while(ip2 < &rp->i_addr[8])
			*ip1++ = *ip2++;
		if(rp->i_flag&IACC) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		} else
			ip1 =+ 2;
		if(rp->i_flag&IUPD) {
			*ip1++ = time.hiword;
			*ip1++ = time.loword;
		}
		rp->i_flag =& ~(IUPD|IACC);
		bdwrite(bp);
	}
}

/*
 * Free all the disk blocks associated with the specified inode structure.
 * The blocks of the file are removed in reverse order. This FILO
 * algorithm will tend to maintain
 * a contiguous free list much longer than FIFO.
 */
itrunc(ip)
int *ip;
{
	register *rp, *bp, *cp;
	int *dp, *ep;

	rp = ip;
	if((rp->i_mode&(IFCHR&IFBLK)) != 0)
		return;
	for(ip = &rp->i_addr[7]; ip >= &rp->i_addr[0]; ip--)
	if(*ip) {
		if((rp->i_mode&ILARG) != 0) {
			bp = bread(rp->i_dev, *ip);
			for(cp = bp->b_addr+510; cp >= bp->b_addr; cp--)
			if(*cp) {
				free(rp->i_dev, *cp);
			}







Jun 19 11:27 1978  iget.c Page 4


			brelse(bp);
		}
		free(rp->i_dev, *ip);
		*ip = 0;
	}
	rp->i_mode =& ~ILARG;
	rp->i_size0 = 0;
	rp->i_size1 = 0;
	rp->i_flag =| IUPD;
}

/*
 * Make a new file.
 */
maknode(mode)
{
	register *ip;

	ip = ialloc(u.u_pdir->i_dev);
	if (ip==NULL) {
		iput(u.u_pdir);
		return(NULL);
	}
	ip->i_flag =| IACC|IUPD;
	ip->i_mode = mode|IALLOC;
	ip->i_nlink = 1;
	ip->i_uid = u.u_uid;
	ip->i_gid = u.u_gid;
	wdir(ip);
	return(ip);
}

/*
 * Write a directory entry with parameters left as side effects
 * to a call to namei.
 */
wdir(ip)
int *ip;
{
	register char *cp1, *cp2;

	u.u_dent.u_ino = ip->i_number;
	cp1 = &u.u_dent.u_name[0];
	for(cp2 = &u.u_dbuf[0]; cp2 < &u.u_dbuf[DIRSIZ];)
		*cp1++ = *cp2++;
	u.u_count = DIRSIZ+2;
	u.u_segflg = 1;
	u.u_base = &u.u_dent;
	writei(u.u_pdir);
	iput(u.u_pdir);
}












Jun 19 11:27 1978  main.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/inode.h"
#include "../hd/seg.h"

#define	CLOCK1	0177546
#define	CLOCK2	0172540
/*
 * Icode is the octal bootstrap program executed in user mode
 * to bring up the system.
 */
int	icode[]
{
	0104413,	/* sys exec; init; initp */
	0000014,
	0000010,
	0000777,	/* br . */
	0000014,	/* initp: init; 0 */
	0000000,
	0062457,	/* init: </etc/init\0> */
	0061564,
	0064457,
	0064556,
	0000164,
};

/*
 * Initialization code.
 * Called from mch.s as soon as a stack and segmentation
 * have been established.
 * Functions:
 *	clear and free user core
 *	find which clock is configured
 *	hand craft 0th process
 *	call all initialization routines
 *	fork - process 0 to schedule
 *	     - process 1 execute bootstrap
 *
 * panic: no clock -- neither clock responds
 * loop at loc 6 in user mode -- /etc/init
 *	cannot be executed.
 */
main()
{
	register i;

	/*
	 * zero and free all of core
	 */

	printf("\nUnix system %s\n",&pwbname);
	printf("\nRestricted rights:\n");







Jun 19 11:27 1978  main.c Page 2


	printf("Use, duplication or disclosure is subject to restrictions\n");
	printf("stated in your contract with Western Electric Company, Inc.\n");
	i = *ka6 + USIZE;
	UISD->r[0] = 077406;
	for(;;) {
		UISA->r[0] = i;
		if(fuibyte(0) < 0)
			break;
		clearseg(i);
		maxmem++;
		mfree(coremap, 1, i);
		i++;
	}
	printf("\nAvailable user memory = %l * 32 words\n",maxmem);
	maxmem = min(maxmem, MAXMEM);
	mfree(swapmap, nswap, swplo);

	/*
	 * determine clock
	 */

	UISA->r[7] = ka6[1]; /* io segment */
	UISD->r[7] = 077406;
	lks = CLOCK1;
	if(fuiword(lks) == -1) {
		lks = CLOCK2;
		if(fuiword(lks) == -1)
			panic("no clock");
	}

	/*
	 * set up system process
	 */

	proc[0].p_addr = *ka6;
	proc[0].p_size = USIZE;
	proc[0].p_stat = SRUN;
	proc[0].p_flag =| SLOAD|SSYS;
	u.u_procp = &proc[0];

	/*
	 * set up 'known' i-nodes
	 */

	*lks = 0115;
	cinit();
	binit();
	iinit();
	rootdir = iget(rootdev, ROOTINO);
	rootdir->i_flag =& ~ILOCK;
	u.u_cdir = iget(rootdev, ROOTINO);
	u.u_cdir->i_flag =& ~ILOCK;

	/*
	 * make init process
	 * enter scheduling loop







Jun 19 11:27 1978  main.c Page 3


	 * with system process
	 */

	if(newproc()) {
		expand(USIZE+1);
		estabur(0, 1, 0, 0, RO);
		copyout(icode, 0, sizeof icode);
		/*
		 * Return goes to loc. 0 of user init
		 * code just copied out.
		 */
		return;
	}
	sched();
}

/*
 * Load the user hardware segmentation
 * registers from the software prototype.
 * The software registers must have
 * been setup prior by estabur.
 */
sureg()
{
	register *udp, *uap, *rdp;
	int *rap, daddr, taddr, *limudp;

	taddr = daddr = u.u_procp->p_addr;
	if (udp=u.u_procp->p_textp)
		taddr = udp->x_caddr;
	limudp = &u.u_uisd[16];
	if (cputype==40)
		limudp = &u.u_uisd[8];
	rap = UISA;
	rdp = UISD;
	uap = &u.u_uisa[0];
	for (udp = &u.u_uisd[0]; udp < limudp;) {
		*rap++ = *uap++ + (*udp&TX? taddr: daddr);
		*rdp++ = *udp++;
	}
}

/*
 * Set up software prototype segmentation
 * registers to implement the 3 pseudo
 * text,data,stack segment sizes passed
 * as arguments.
 * The argument sep specifies if the
 * text and data+stack segments are to
 * be separated.
 * The last argument determines whether the text
 * segment is read-write or read-only.
 */
estabur(nt, nd, ns, sep, xrw)
{
	register a, *ap, *dp;







Jun 19 11:27 1978  main.c Page 4



	if(checkur(nt, nd, ns, sep))
		return(-1);
	a = 0;
	ap = &u.u_uisa[0];
	dp = &u.u_uisd[0];
	while(nt >= 128) {
		*dp++ = (127<<8) | xrw|TX;
		*ap++ = a;
		a =+ 128;
		nt =- 128;
	}
	if(nt) {
		*dp++ = ((nt-1)<<8) | xrw|TX;
		*ap++ = a;
	}
	if(sep)
	while(ap < &u.u_uisa[8]) {
		*ap++ = 0;
		*dp++ = 0;
	}
	a = USIZE;
	while(nd >= 128) {
		*dp++ = (127<<8) | RW;
		*ap++ = a;
		a =+ 128;
		nd =- 128;
	}
	if(nd) {
		*dp++ = ((nd-1)<<8) | RW;
		*ap++ = a;
		a =+ nd;
	}
	while(ap < &u.u_uisa[8]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	if(sep)
	while(ap < &u.u_uisa[16]) {
		*dp++ = 0;
		*ap++ = 0;
	}
	a =+ ns;
	while(ns >= 128) {
		a =- 128;
		ns =- 128;
		*--dp = (127<<8) | RW;
		*--ap = a;
	}
	if(ns) {
		*--dp = ((128-ns)<<8) | RW | ED;
		*--ap = a-128;
	}
	if(!sep) {
		ap = &u.u_uisa[0];
		dp = &u.u_uisa[8];







Jun 19 11:27 1978  main.c Page 5


		while(ap < &u.u_uisa[8])
			*dp++ = *ap++;
		ap = &u.u_uisd[0];
		dp = &u.u_uisd[8];
		while(ap < &u.u_uisd[8])
			*dp++ = *ap++;
	}
	sureg();
	return(0);

}
checkur(nt, nd, ns, sep)
{
	if(sep) {
		if(cputype == 40)
			goto err;
		if(ctos(nt) > 8 || ctos(nd)+ctos(ns) > 8)
			goto err;
	} else
		if(ctos(nt)+ctos(nd)+ctos(ns) > 8)
			goto err;
	if(nt+nd+ns+USIZE > maxmem)
		goto err;
	return(0);
err:
	u.u_error = ENOMEM;
	return(-1);
}



































Jun 19 11:27 1978  malloc.c Page 1


#include "../hd/param.h"
#include "../hd/systm.h"

/*
 * Allocate 'size' units from the given
 * map. Return the base of the allocated
 * space.
 * In a map, the addresses are increasing and the
 * list is terminated by a 0 size.
 * The core map unit is 64 bytes; the swap map unit
 * is 512 bytes.
 * Algorithm is first-fit.
 */
malloc(mp, size)
struct map *mp;
{
	register int a;
	register struct map *bp;

	for (bp=mp; bp->m_size; bp++) {
		if (bp->m_size >= size) {
			a = bp->m_addr;
			bp->m_addr =+ size;
			if ((bp->m_size =- size) == 0)
				do {
					bp++;
					(bp-1)->m_addr = bp->m_addr;
				} while ((bp-1)->m_size = bp->m_size);
			return(a);
		}
	}
	return(0);
}

/*
 * Free the previously allocated space aa
 * of size units into the specified map.
 * Sort aa into map and combine on
 * one or both ends if possible.
 */
mfree(mp, size, aa)
struct map *mp;
char *aa;
{
	register struct map *bp;
	register int t;
	register char *a;

	a = aa;
	if ((bp = mp)==coremap && runin) {
		runin = 0;
		wakeup(&runin);		/* Wake scheduler when freeing core */
	}
	for (; bp->m_addr<=a && bp->m_size!=0; bp++);
	if (bp>mp && (bp-1)->m_addr+(bp-1)->m_size == a) {
		(bp-1)->m_size =+ size;







Jun 19 11:27 1978  malloc.c Page 2


		if (a+size == bp->m_addr) {
			(bp-1)->m_size =+ bp->m_size;
			while (bp->m_size) {
				bp++;
				(bp-1)->m_addr = bp->m_addr;
				(bp-1)->m_size = bp->m_size;
			}
		}
	} else {
		if (a+size == bp->m_addr && bp->m_size) {
			bp->m_addr =- size;
			bp->m_size =+ size;
		} else if (size) do {
			t = bp->m_addr;
			bp->m_addr = a;
			a = t;
			t = bp->m_size;
			bp->m_size = size;
			bp++;
		} while (size = t);
	}
}









































Jun 19 11:27 1978  nami.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/systm.h"
#include "../hd/buf.h"

/*
 * Convert a pathname into a pointer to
 * an inode. Note that the inode is locked.
 *
 * func = function called to get next char of name
 *	&uchar if name is in user space
 *	&schar if name is in system space
 * flag = 0 if name is sought
 *	1 if name is to be created
 *	2 if name is to be deleted
 */
namei(func, flag)
int (*func)();
{
	register struct inode *dp;
	register c;
	register char *cp;
	int eo, *bp;

	/*
	 * If name starts with '/' start from
	 * root; otherwise start from current dir.
	 */

	dp = u.u_cdir;
	if((c=(*func)()) == '/')
		dp = rootdir;
	iget(dp->i_dev, dp->i_number);
	while(c == '/')
		c = (*func)();
	if(c == '\0' && flag != 0) {
		u.u_error = ENOENT;
		goto out;
	}

cloop:
	/*
	 * Here dp contains pointer
	 * to last component matched.
	 */

	if(u.u_error)
		goto out;
	if(c == '\0')
		return(dp);

	/*
	 * If there is another component,
	 * dp must be a directory and







Jun 19 11:27 1978  nami.c Page 2


	 * must have x permission.
	 */

	if((dp->i_mode&IFMT) != IFDIR || dp->i_nlink==0) {
		u.u_error = ENOTDIR;
		goto out;
	}
	if(access(dp, IEXEC))
		goto out;

	/*
	 * Gather up name into
	 * users' dir buffer.
	 */

	cp = &u.u_dbuf[0];
	while(c!='/' && c!='\0' && u.u_error==0) {
		if(cp < &u.u_dbuf[DIRSIZ])
			*cp++ = c;
		c = (*func)();
	}
	while(cp < &u.u_dbuf[DIRSIZ])
		*cp++ = '\0';
	while(c == '/')
		c = (*func)();
	if(u.u_error)
		goto out;

	/*
	 * Set up to search a directory.
	 */

	u.u_offset[1] = 0;
	u.u_offset[0] = 0;
	u.u_segflg = 1;
	eo = 0;
	u.u_count = ldiv(dp->i_size1, DIRSIZ+2);
	bp = NULL;

eloop:

	/*
	 * If at the end of the directory,
	 * the search failed. Report what
	 * is appropriate as per flag.
	 */

	if(u.u_count == 0) {
		if(bp != NULL)
			brelse(bp);
		if(flag==1 && c=='\0') {
			if(access(dp, IWRITE))
				goto out;
			u.u_pdir = dp;
			if(eo)
				u.u_offset[1] = eo-DIRSIZ-2; else







Jun 19 11:27 1978  nami.c Page 3


				bmap(dp,ldiv(u.u_offset[1],512));	/* check space */
			if (u.u_error)
				goto out;
			return(NULL);
		}
		u.u_error = ENOENT;
		goto out;
	}

	/*
	 * If offset is on a block boundary,
	 * read the next directory block.
	 * Release previous if it exists.
	 */

	if((u.u_offset[1]&0777) == 0) {
		if(bp != NULL)
			brelse(bp);
		bp = bread(dp->i_dev,
			bmap(dp, ldiv(u.u_offset[1], 512)));
	}

	/*
	 * Note first empty directory slot
	 * in eo for possible creat.
	 * String compare the directory entry
	 * and the current component.
	 * If they do not match, go back to eloop.
	 */

	bcopy(bp->b_addr+(u.u_offset[1]&0777), &u.u_dent, (DIRSIZ+2)/2);
	u.u_offset[1] =+ DIRSIZ+2;
	if (u.u_offset[1]==0)
		u.u_error = EFBIG;
	u.u_count--;
	if(u.u_dent.u_ino == 0) {
		if(eo == 0)
			eo = u.u_offset[1];
		goto eloop;
	}
	for(cp = &u.u_dbuf[0]; cp < &u.u_dbuf[DIRSIZ]; cp++)
		if(*cp != cp[u.u_dent.u_name - u.u_dbuf])
			goto eloop;

	/*
	 * Here a component matched in a directory.
	 * If there is more pathname, go back to
	 * cloop, otherwise return.
	 */

	if(bp != NULL)
		brelse(bp);
	if(flag==2 && c=='\0') {
		if(access(dp, IWRITE))
			goto out;
		return(dp);







Jun 19 11:27 1978  nami.c Page 4


	}
	bp = dp->i_dev;
	iput(dp);
	dp = iget(bp, u.u_dent.u_ino);
	if(dp == NULL)
		return(NULL);
	goto cloop;

out:
	iput(dp);
	return(NULL);
}

/*
 * Return the next character from the
 * kernel string pointed at by dirp.
 */
schar()
{

	return(*u.u_dirp++ & 0377);
}

/*
 * Return the next character from the
 * user string pointed at by dirp.
 */
uchar()
{
	register c;

	c = fubyte(u.u_dirp++);
	if(c == -1)
		u.u_error = EFAULT;
	return(c);
}



























Jun 19 11:27 1978  pipe.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/reg.h"

/*
 * Max allowable buffering per pipe.
 * This is also the max size of the
 * file created to implement the pipe.
 * If this size is bigger than 4096,
 * pipes will be implemented in LARG
 * files, which is probably not good.
 */
#define	PIPSIZ	4096

/*
 * The sys-pipe entry.
 * Allocate an inode on the root device.
 * Allocate 2 file structures.
 * Put it all together with flags.
 */
pipe()
{
	register *ip, *rf, *wf;
	int r;

	ip = ialloc(rootdev);
	if(ip == NULL)
		return;
	rf = falloc();
	if(rf == NULL) {
		iput(ip);
		return;
	}
	r = u.u_ar0[R0];
	wf = falloc();
	if(wf == NULL) {
		rf->f_count = 0;
		u.u_ofile[r] = NULL;
		iput(ip);
		return;
	}
	u.u_ar0[R1] = u.u_ar0[R0];
	u.u_ar0[R0] = r;
	wf->f_flag = FWRITE|FPIPE;
	wf->f_inode = ip;
	rf->f_flag = FREAD|FPIPE;
	rf->f_inode = ip;
	ip->i_count = 2;
	ip->i_flag = IACC|IUPD;
	ip->i_mode = IALLOC;
}








Jun 19 11:27 1978  pipe.c Page 2


/*
 * Read call directed to a pipe.
 */
readp(fp)
int *fp;
{
	register *rp, *ip;

	rp = fp;
	ip = rp->f_inode;

loop:
	/*
	 * Very conservative locking.
	 */

	plock(ip);
	/*
	 * If nothing in the pipe, wait.
	 */
	if (ip->i_size1==0) {
		/*
		 * If there are not both reader and
		 * writer active, return without
		 * satisfying read.
		 */
		prele(ip);
		if(ip->i_count < 2)
			return;
		ip->i_mode =| IREAD;
		sleep(ip+2, PPIPE);
		goto loop;
	}

	/*
	 * Read and return
	 */

	u.u_offset[0] = 0;
	u.u_offset[1] = rp->f_offset[1];
	readi(ip);
	rp->f_offset[1] = u.u_offset[1];
	/*
	 * If reader has caught up with writer, reset
	 * offset and size to 0.
	 */
	if (rp->f_offset[1] == ip->i_size1) {
		rp->f_offset[1] = 0;
		ip->i_size1 = 0;
		if (ip->i_mode&IWRITE) {
			ip->i_mode =& ~IWRITE;
			wakeup(ip+1);
		}
	}
	prele(ip);
}







Jun 19 11:27 1978  pipe.c Page 3



/*
 * Write call directed to a pipe.
 */
writep(fp)
{
	register *rp, *ip, c;

	rp = fp;
	ip = rp->f_inode;
	c = u.u_count;

loop:

	/*
	 * If all done, return.
	 */

	plock(ip);
	if(c == 0) {
		prele(ip);
		u.u_count = 0;
		return;
	}

	/*
	 * If there are not both read and
	 * write sides of the pipe active,
	 * return error and signal too.
	 */

	if(ip->i_count < 2) {
		prele(ip);
		u.u_error = EPIPE;
		psignal(u.u_procp, SIGPIPE);
		return;
	}

	/*
	 * If the pipe is full,
	 * wait for reads to deplete
	 * and truncate it.
	 */

	if(ip->i_size1 == PIPSIZ) {
		ip->i_mode =| IWRITE;
		prele(ip);
		sleep(ip+1, PPIPE);
		goto loop;
	}

	/*
	 * Write what is possible and
	 * loop back.
	 */








Jun 19 11:27 1978  pipe.c Page 4


	u.u_offset[0] = 0;
	u.u_offset[1] = ip->i_size1;
	u.u_count = min(c, PIPSIZ-u.u_offset[1]);
	c =- u.u_count;
	writei(ip);
	prele(ip);
	if(ip->i_mode&IREAD) {
		ip->i_mode =& ~IREAD;
		wakeup(ip+2);
	}
	goto loop;
}

/*
 * Lock a pipe.
 * If its already locked,
 * set the WANT bit and sleep.
 */
plock(ip)
int *ip;
{
	register *rp;

	rp = ip;
	while(rp->i_flag&ILOCK) {
		rp->i_flag =| IWANT;
		sleep(rp, PPIPE);
	}
	rp->i_flag =| ILOCK;
}

/*
 * Unlock a pipe.
 * If WANT bit is on,
 * wakeup.
 * This routine is also used
 * to unlock inodes in general.
 */
prele(ip)
int *ip;
{
	register *rp;

	rp = ip;
	rp->i_flag =& ~ILOCK;
	if(rp->i_flag&IWANT) {
		rp->i_flag =& ~IWANT;
		wakeup(rp);
	}
}













Jun 19 11:27 1978  prf.c Page 1


#
#include "../hd/param.h"
#include "../hd/seg.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Address and structure of the
 * KL-11 console device registers.
 */
struct
{
	int	rsr;
	int	rbr;
	int	xsr;
	int	xbr;
};

/*
 * In case console is off,
 * panicstr contains argument to last
 * call to panic.
 */

char	*panicstr;

/*
 * Scaled down version of C Library printf.
 * Only %s %l %d (==%l) %o are recognized.
 * Used to print diagnostic information
 * directly on console tty.
 * Since it is not interrupt driven,
 * all system activities are pretty much
 * suspended.
 * Printf should not be used for chit-chat.
 */
printf(fmt,x1)
char fmt[];
{
	register char *s;
	register *adx, c;

	adx = &x1;
loop:
	while((c = *fmt++) != '%') {
		if(c == '\0')
			return;
		putchar(c);
	}
	c = *fmt++;
	if(c == 'd' || c == 'l' || c == 'o')
		printn(*adx, c=='o'? 8: 10);
	if(c == 's') {
		s = *adx;
		while(c = *s++)
			putchar(c);







Jun 19 11:27 1978  prf.c Page 2


	}
	adx++;
	goto loop;
}

/*
 * Print an unsigned integer in base b.
 */
printn(n, b)
{
	register a;

	if(a = ldiv(n, b))
		printn(a, b);
	putchar(lrem(n, b) + '0');
}

/*
 * Print a character on console.
 * Attempts to save and restore device
 * status.
 * If the switches are 0, all
 * printing is inhibited.
 */
putchar(c)
{
	register rc, s;

	rc = c;
	if(SW->integ == 0)
		return;
	while((KL->xsr&0200) == 0)
		;
	if(rc == 0)
		return;
	s = KL->xsr;
	KL->xsr = 0;
	KL->xbr = rc;
	if(rc == '\n') {
		putchar('\r');
		putchar(0177);
		putchar(0177);
	}
	putchar(0);
	KL->xsr = s;
}

/*
 * Panic is called on unresolvable
 * fatal errors.
 * It syncs, prints "panic: mesg" and
 * then loops.
 */
panic(s)
char *s;
{







Jun 19 11:27 1978  prf.c Page 3


	panicstr = s;
	update();
	printf("panic: %s\n", s);
	for(;;)
		idle();
}

/*
 * prdev prints a warning message of the
 * form "mesg on dev x/y".
 * x and y are the major and minor parts of
 * the device argument.
 */
prdev(str, dev)
{

	printf("%s on dev %l/%l\n", str, major(dev), minor(dev));
}

/*
 * deverr prints a diagnostic from
 * a device driver.
 * It prints the device, block number,
 * and an octal word (usually some error
 * status register) passed as argument.
 */
deverror(bp, o1, o2)
int *bp;
{
	register *rbp;

	if(SW->integ&01)
		return;
	rbp = bp;
	prdev("err", rbp->b_dev);
	printf("bn%l er%o %o\n", rbp->b_blkno, o1, o2);
}


























Jun 19 11:27 1978  pwbsys.c Page 1


#
#include "../hd/param.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/inode.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/var.h"

pwbsys()
{
	extern uchar;
	register i;
	register *p;
	register struct buf *bp;

	switch(u.u_arg[0]) {

case 0:		/* uname */
	if (copyout(&pwbname, u.u_ar0[R0], 8))
		u.u_error = EFAULT;
	return;

case 1:		/* udata */
	if (u.u_ar0[R1]) {
		if(suser())
			i = copyin(u.u_ar0[R0],u.u_udata,32); else
			return;
	} else
		i = copyout(u.u_udata,u.u_ar0[R0],32);
	if (i)
		u.u_error = EFAULT;
	return;

case 2:		/* ustat */
	for(i=0; i<v.v_mount; i++) {
		p = &mount[i];
		if(p->m_bufp!=NULL && p->m_dev==u.u_ar0[R1]) {
			p = p->m_bufp->b_addr;
			if(copyout(&p->s_tfree, u.u_ar0[R0], 16))
				u.u_error = EFAULT;
			return;
		}
	}
	u.u_error = EINVAL;
	return;

case 3:		/* utime */
	if (!suser())
		return;
	u.u_dirp = u.u_ar0[R1];
	if ((p = namei(&uchar, 0))==NULL)
		return;
	if (getfs(p->i_dev)->s_ronly) {
		u.u_error = EROFS;







Jun 19 11:27 1978  pwbsys.c Page 2


		return;
	}
	i = p->i_number+31;
	bp = bread(p->i_dev, ldiv(i,16));
	copyin (u.u_ar0[R0], bp->b_addr+32*lrem(i,16)+24, 8);
	p->i_flag =& ~(IACC|IUPD);
	bdwrite(bp);
	iput(p);
	return;

default:
	u.u_error = EFAULT;
	}
}

















































Jun 19 11:27 1978  rdwri.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/conf.h"
#include "../hd/systm.h"

/*
 * Read the file corresponding to
 * the inode pointed at by the argument.
 * The actual read arguments are found
 * in the variables:
 *	u_base		core address for destination
 *	u_offset	byte offset in file
 *	u_count		number of bytes to read
 *	u_segflg	read to kernel/user/user I
 */
readi(aip)
struct inode *aip;
{
	int *bp;
	int lbn, bn, on;
	register dn, n;
	register struct inode *ip;

	ip = aip;
	if(u.u_count == 0)
		return;
	ip->i_flag =| IACC;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_read)(minor(ip->i_addr[0]));
		return;
	}

	do {
		lbn = bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			dn = dpcmp(ip->i_size0&0377, ip->i_size1,
				u.u_offset[0], u.u_offset[1]);
			if(dn <= 0)
				return;
			n = min(n, dn);
			if ((bn = bmap(ip, lbn)) == 0)
				return;
			dn = ip->i_dev;
		} else {
			dn = ip->i_addr[0];
			rablock = bn+1;
		}
		if ((ip->i_lastr+1) == lbn && (on+n) == 512)
			bp = breada(dn, bn, rablock);
		else
			bp = bread(dn, bn);







Jun 19 11:27 1978  rdwri.c Page 2


		if ((on+n) == 512)
			ip->i_lastr = lbn;
		if (bp->b_resid!=0)
			n = 0;
		iomove(bp, on, n, B_READ);
		brelse(bp);
	} while(u.u_error==0 && u.u_count && n);
}

/*
 * Write the file corresponding to
 * the inode pointed at by the argument.
 * The actual write arguments are found
 * in the variables:
 *	u_base		core address for source
 *	u_offset	byte offset in file
 *	u_count		number of bytes to write
 *	u_segflg	write to kernel/user/user I
 */
writei(aip)
struct inode *aip;
{
	int *bp;
	int n, on;
	register dn, bn;
	register struct inode *ip;

	ip = aip;
	ip->i_flag =| IACC|IUPD;
	if((ip->i_mode&IFMT) == IFCHR) {
		(*cdevsw[major(ip->i_addr[0])].d_write)(minor(ip->i_addr[0]));
		return;
	}
	if (u.u_count == 0)
		return;

	do {
		bn = lshift(u.u_offset, -9);
		on = u.u_offset[1] & 0777;
		n = min(512-on, u.u_count);
		if((ip->i_mode&IFMT) != IFBLK) {
			if ((bn = bmap(ip, bn)) == 0)
				return;
			dn = ip->i_dev;
		} else
			dn = ip->i_addr[0];
		if(n == 512) 
			bp = getblk(dn, bn); else
			bp = bread(dn, bn);
		iomove(bp, on, n, B_WRITE);
		if(u.u_error != 0)
			brelse(bp); else
		if ((u.u_offset[1]&0777)==0)
			bawrite(bp); else
			bdwrite(bp);
		if(dpcmp(ip->i_size0&0377, ip->i_size1,







Jun 19 11:27 1978  rdwri.c Page 3


		  u.u_offset[0], u.u_offset[1]) < 0 &&
		  (ip->i_mode&(IFBLK&IFCHR)) == 0) {
			ip->i_size0 = u.u_offset[0];
			ip->i_size1 = u.u_offset[1];
		}
		ip->i_flag =| IUPD;
	} while(u.u_error==0 && u.u_count!=0);
}

/*
 * Return the logical maximum
 * of the 2 arguments.
 */
max(a, b)
char *a, *b;
{

	if(a > b)
		return(a);
	return(b);
}

/*
 * Return the logical minimum
 * of the 2 arguments.
 */
min(a, b)
char *a, *b;
{

	if(a < b)
		return(a);
	return(b);
}

/*
 * Move 'an' bytes at byte location
 * &bp->b_addr[o] to/from (flag) the
 * user/kernel (u.segflg) area starting at u.base.
 * Update all the arguments by the number
 * of bytes moved.
 *
 * There are 2 algorithms,
 * if source address, dest address and count
 * are all even in a user copy,
 * then the machine language copyin/copyout
 * is called.
 * If not, its done byte-by-byte with
 * cpass and passc.
 */
iomove(bp, o, an, flag)
struct buf *bp;
{
	register char *cp;
	register int n, t;








Jun 19 11:27 1978  rdwri.c Page 4


	if ((n = an)==0 || u.u_error)
		return;
	cp = bp->b_addr + o;
	if(u.u_segflg!=1 && ((n | cp | u.u_base)&01)==0) {
		if (flag==B_WRITE)
			if (u.u_segflg==0)
				cp = copyin(u.u_base, cp, n);
			else
				cp = copyiin(u.u_base, cp, n);
		else
			if (u.u_segflg==0)
				cp = copyout(cp, u.u_base, n);
			else
				cp = copyiout(cp, u.u_base, n);
		if (cp) {
			u.u_error = EFAULT;
			return;
		}
		u.u_base =+ n;
		dpadd(u.u_offset, n);
		u.u_count =- n;
		return;
	}
	if (flag==B_WRITE) {
		while(n--) {
			if ((t = cpass()) < 0)
				return;
			*cp++ = t;
		}
	} else
		while (n--)
			if(passc(*cp++) < 0)
				return;
}





























Jun 19 11:27 1978  sig.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/inode.h"
#include "../hd/reg.h"
#include "../hd/text.h"
#include "../hd/seg.h"
#include "../hd/var.h"

/*
 * Priority for tracing
 */
#define	IPCPRI	0

/*
 * Structure to access an array of integers.
 */
struct
{
	int	inta[];
};

/*
 * Tracing variables.
 * Used to pass trace command from
 * parent to child being traced.
 * This data base cannot be
 * shared and is locked
 * per user.
 */
struct
{
	int	ip_lock;
	int	ip_req;
	int	ip_addr;
	int	ip_data;
} ipc;

/*
 * Send the specified signal to
 * all processes with 'pgrp' as
 * process group.
 * Called by tty.c for quits and
 * interrupts.
 */
signal(apgrp, sig)
{
	register struct proc *p;
	register pgrp;

	if ((pgrp = apgrp)==0)
		return;
	for(p = &proc[0]; p < v.ve_proc; p++)
		if(p->p_pgrp == pgrp)







Jun 19 11:27 1978  sig.c Page 2


			psignal(p, sig);
}

/*
 * Send the specified signal to
 * the specified process.
 */
psignal(p, sig)
int *p;
char *sig;
{
	register *rp, a;

	a = sig;
	if(a > NSIG)
		return;
	rp = p;
	if(a)
		rp->p_sig =| 1<<(a-1);
	if(rp->p_pri > PUSER)
		rp->p_pri = PUSER;
	if(rp->p_stat == SSLEEP && rp->p_pri > 0)
		setrun(rp);
}

/*
 * Returns true if the current
 * process has a signal to process.
 * This is asked at least once
 * each time a process enters the
 * system.
 * A signal does not do anything
 * directly to a process; it sets
 * a flag that asks the process to
 * do something to itself.
 */
issig()
{
	register n;
	register struct proc *p;

	p = u.u_procp;
	while(p->p_sig) {
		n = fsig(p);
		if((u.u_signal[n-1]&1) == 0 || (p->p_flag&STRC))
			return(n);
		p->p_sig =& ~(1<<(n-1));
	}
	return(0);
}

/*
 * Enter the tracing STOP state.
 * In this state, the parent is
 * informed and the process is able to
 * receive commands from the parent.







Jun 19 11:27 1978  sig.c Page 3


 */
stop()
{
	register struct proc *pp, *cp;

loop:
	cp = u.u_procp;
	if(cp->p_ppid != 1)
	for (pp = &proc[0]; pp < v.ve_proc; pp++)
		if (pp->p_pid == cp->p_ppid) {
			wakeup(pp);
			cp->p_stat = SSTOP;
			swtch();
			if ((cp->p_flag&STRC)==0 || procxmt())
				return;
			goto loop;
		}
	exit();
}

/*
 * Perform the action specified by
 * the current signal.
 * The usual sequence is:
 *	if(issig())
 *		psig();
 */
psig()
{
	register n, p;
	register *rp;

	rp = u.u_procp;
	if (rp->p_flag&STRC)
		stop();
	n = fsig(rp);
	if (n==0)
		return;
	rp->p_sig =& ~(1<<(n-1));
	if((p=u.u_signal[n-1]) != 0) {
		u.u_error = 0;
		if(n != SIGINS && n != SIGTRC)
			u.u_signal[n-1] = 0;
		n = u.u_ar0[R6] - 4;
		grow(n);
		suword(n+2, u.u_ar0[RPS]);
		suword(n, u.u_ar0[R7]);
		u.u_ar0[R6] = n;
		u.u_ar0[RPS] =& ~TBIT;
		u.u_ar0[R7] = p;
		return;
	}
	switch(n) {

	case SIGQIT:
	case SIGINS:







Jun 19 11:27 1978  sig.c Page 4


	case SIGTRC:
	case SIGIOT:
	case SIGEMT:
	case SIGFPT:
	case SIGBUS:
	case SIGSEG:
	case SIGSYS:
		u.u_arg[0] = n;
		if(core())
			n =+ 0200;
	}
	u.u_arg[0] = (u.u_ar0[R0]<<8) | n;
	exit();
}

/*
 * find the signal in bit-position
 * representation in p_sig.
 */
fsig(p)
struct proc *p;
{
	register n, i;
	register char *cp;

	n = p->p_sig;
	for(i=1; i<=NSIG; i++) {
		if(n & 1)
			return(i);
		n =>> 1;
	}
	return(0);
}

/*
 * Create a core image on the file "core"
 * If you are looking for protection glitches,
 * there are probably a wealth of them here
 * when this occurs to a suid command.
 *
 * It writes USIZE block of the
 * user.h area followed by the entire
 * data+stack segments.
 */
core()
{
	register s, *ip;
	extern schar;

	u.u_error = 0;
	u.u_dirp = "core";
	ip = namei(&schar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return(0);
		ip = maknode(0666);







Jun 19 11:27 1978  sig.c Page 5


		if (ip==NULL)
			return(0);
	}
	if(!access(ip, IWRITE) &&
	   (ip->i_mode&IFMT) == 0 &&
	   u.u_uid == u.u_ruid) {
		itrunc(ip);
		u.u_offset[0] = 0;
		u.u_offset[1] = 0;
		u.u_base = &u;
		u.u_count = USIZE*64;
		u.u_segflg = 1;
		writei(ip);
		s = u.u_procp->p_size - USIZE;
		estabur(0, s, 0, 0, RO);
		u.u_base = 0;
		u.u_count = s*64;
		u.u_segflg = 0;
		writei(ip);
	}
	iput(ip);
	return(u.u_error==0);
}

/*
 * grow the stack to include the SP
 * true return if successful.
 */

grow(sp)
char *sp;
{
	register a, si, i;

	if(sp >= -u.u_ssize*64)
		return(0);
	si = ldiv(-sp, 64) - u.u_ssize + SINCR;
	if(si <= 0)
		return(0);
	if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep, RO))
		return(0);
	expand(u.u_procp->p_size+si);
	a = u.u_procp->p_addr + u.u_procp->p_size;
	for(i=u.u_ssize; i; i--) {
		a--;
		copyseg(a-si, a);
	}
	for(i=si; i; i--)
		clearseg(--a);
	u.u_ssize =+ si;
	return(1);
}

/*
 * sys-trace system call.
 */







Jun 19 11:27 1978  sig.c Page 6


ptrace()
{
	register struct proc *p;
	register struct text *xp;

	if (u.u_arg[2] <= 0) {
		u.u_procp->p_flag =| STRC;
		return;
	}
	for (p=proc; p < v.ve_proc; p++) 
		if (p->p_stat==SSTOP
		 && p->p_pid==u.u_arg[0]
		 && p->p_ppid==u.u_procp->p_pid)
			goto found;
	u.u_error = ESRCH;
	return;

    found:
	while (ipc.ip_lock)
		sleep(&ipc, IPCPRI);
	ipc.ip_lock = p->p_pid;
	ipc.ip_data = u.u_ar0[R0];
	ipc.ip_addr = u.u_arg[1] & ~01;
	ipc.ip_req = u.u_arg[2];
	p->p_flag =& ~SWTED;
	setrun(p);
	while (ipc.ip_req > 0)
		sleep(&ipc, IPCPRI);
	u.u_ar0[R0] = ipc.ip_data;
	if (ipc.ip_req < 0)
		u.u_error = EIO;
	ipc.ip_lock = 0;
	wakeup(&ipc);
}

/*
 * Code that the child process
 * executes to implement the command
 * of the parent process in tracing.
 */
procxmt()
{
	register int i;
	register int *p;
	register struct text *xp;

	if (ipc.ip_lock != u.u_procp->p_pid)
		return(0);
	i = ipc.ip_req;
	ipc.ip_req = 0;
	wakeup(&ipc);
	switch (i) {

	/* read user I */
	case 1:
		if (fuibyte(ipc.ip_addr) == -1)







Jun 19 11:27 1978  sig.c Page 7


			goto error;
		ipc.ip_data = fuiword(ipc.ip_addr);
		break;

	/* read user D */
	case 2:
		if (fubyte(ipc.ip_addr) == -1)
			goto error;
		ipc.ip_data = fuword(ipc.ip_addr);
		break;

	/* read u */
	case 3:
		i = ipc.ip_addr;
		if (i<0 || i >= (USIZE<<6))
			goto error;
		ipc.ip_data = u.inta[i>>1];
		break;

	/* write user I */
	/* Must set up to allow writing */
	case 4:
		/*
		 * If text, must assure exclusive use
		 */
		if (xp = u.u_procp->p_textp) {
			if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
				goto error;
			xp->x_iptr->i_flag =& ~ITEXT;
		}
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RW);
		i = suiword(ipc.ip_addr, 0);
		suiword(ipc.ip_addr, ipc.ip_data);
		estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RO);
		if (i<0)
			goto error;
		if (xp)
			xp->x_flag =| XWRIT;
		break;

	/* write user D */
	case 5:
		if (suword(ipc.ip_addr, 0) < 0)
			goto error;
		suword(ipc.ip_addr, ipc.ip_data);
		break;

	/* write u */
	case 6:
		p = &u.inta[ipc.ip_addr>>1];
		if (p >= u.u_fsav && p < &u.u_fsav[25])
			goto ok;
		for (i=0; i<9; i++)
			if (p == &u.u_ar0[regloc[i]])
				goto ok;
		goto error;







Jun 19 11:27 1978  sig.c Page 8


	ok:
		if (p == &u.u_ar0[RPS]) {
			ipc.ip_data =| 0170000;	/* assure user space */
			ipc.ip_data =& ~0340;	/* priority 0 */
		}
		*p = ipc.ip_data;
		break;

	/* set signal and continue */
	case 7:
		u.u_procp->p_sig = 0;
		psignal(u.u_procp, ipc.ip_data);
		return(1);

	/* force exit */
	case 8:
		exit();

	default:
	error:
		ipc.ip_req = -1;
	}
	return(0);
}







































Jun 19 11:27 1978  slp.c Page 1


#
#include "../hd/param.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/text.h"
#include "../hd/systm.h"
#include "../hd/file.h"
#include "../hd/inode.h"
#include "../hd/buf.h"
#include "../hd/var.h"

/*
 * Give up the processor till a wakeup occurs
 * on chan, at which time the process
 * enters the scheduling queue at priority pri.
 * The most important effect of pri is that when
 * pri<=0 a signal cannot disturb the sleep;
 * if pri>0 signals will be processed.
 * Callers of this routine must be prepared for
 * premature return, and check that the reason for
 * sleeping has gone away.
 */
sleep(chan, pri)
{
	register *rp, s;

	s = PS->integ;
	rp = u.u_procp;
	spl6();
	rp->p_stat = SSLEEP;
	rp->p_wchan = chan;
	rp->p_pri = pri;
	if(pri > 0) {
		if(issig()) {
			rp->p_wchan = 0;
			rp->p_stat = SRUN;
			spl0();
			goto psig;
		}
		spl0();
		swtch();
		if(issig())
			goto psig;
	} else {
		spl0();
		swtch();
	}
	PS->integ = s;
	return;

	/*
	 * If priority was low (>0) and
	 * there has been a signal,
	 * execute non-local goto to
	 * the qsav location.
	 * (see trap1/trap.c)







Jun 19 11:27 1978  slp.c Page 2


	 */
psig:
	aretu(u.u_qsav);
}

/*
 * Wake up all processes sleeping on chan.
 */
wakeup(chan)
{
	register struct proc *p;
	register c, i;

	c = chan;
	p = &proc[0];
	i = v.ve_proc;
	do {
		if(p->p_wchan == c && p->p_stat==SSLEEP)
			setrun(p);
		p++;
	} while(p != i);
}

setrq(p)
struct proc *p;
{
	register struct proc *q;
	register s;

	s = PS->integ;
	spl6();
	for(q=runq; q!=NULL; q=q->p_link)
		if(q == p) {
			printf("proc on q\n");
			goto out;
		}
	p->p_link = runq;
	runq = p;
out:
	PS->integ = s;
}

/*
 * Set the process running;
 * arrange for it to be swapped in if necessary.
 */
setrun(p)
{
	register struct proc *rp;

	rp = p;
	rp->p_wchan = 0;
	rp->p_stat = SRUN;
	setrq(p);
	if((rp->p_flag&SLOAD)==0) {
		rp->p_time = 0;







Jun 19 11:27 1978  slp.c Page 3


		if(runout != 0) {
			runout = 0;
			setrun(&proc[0]);
		}
	} else
		if(rp->p_pri < curpri)
			runrun++;
}

/*
 * Set user priority.
 * The rescheduling flag (runrun)
 * is set if the priority is better
 * than the currently running process.
 */
setpri(up)
{
	register *pp, p;

	pp = up;
	p = pp->p_cpu/4;
	p =+ PUSER + pp->p_nice;
	if(p > 127)
		p = 127;
	pp->p_pri = p;
	return(p);
}

/*
 * The main loop of the scheduling (swapping)
 * process.
 * The basic idea is:
 *  see if anyone wants to be swapped in;
 *  swap out processes until there is room;
 *  swap him in;
 *  repeat.
 * The runout flag is set whenever someone is swapped out.
 * Sched sleeps on it awaiting work.
 *
 * Sched sleeps on runin whenever it cannot find enough
 * core (by swapping out or otherwise) to fit the
 * selected swapped process.  It is awakend when the
 * core situation changes and in any event once per second.
 */
sched()
{
	register struct proc *rp, *p;
	register outage, inage;
	int swapri, a;

	/*
	 * find user to swap in;
	 * of users ready, select one out longest
	 */

loop:







Jun 19 11:27 1978  slp.c Page 4


	spl6();
	outage = -1;
	for(rp = &proc[0]; rp < v.ve_proc; rp++)
	if (rp->p_stat==SRUN && (rp->p_flag&SLOAD)==0 &&
	    rp->p_time > outage) {
		p = rp;
		outage = rp->p_time;
	}
	/*
	 * If there is no one there, wait.
	 */
	if (outage<0) {
		runout++;
		sleep(&runout, PSWP);
		goto loop;
	}
	spl0();

	/*
	 * See if there is core for that process;
	 * if so, swap it in.
	 */

	if (swapin(p))
		goto loop;

	/*
	 * none found.
	 */

	spl6();
	swapri = 0;
	inage = 0;
	for(rp = &proc[0]; rp < v.ve_proc; rp++) {
		if ((rp->p_flag&(SSYS|SLOCK|SLOAD))!=SLOAD)
			continue;
		if (rp->p_textp && rp->p_textp->x_flag&XLOCK)
			continue;
		if(rp->p_stat==SSLEEP || rp->p_stat==SSTOP) {
			a = (rp->p_pri>>1) + rp->p_time;
			if(a>swapri) {
				p = rp;
				swapri = a;
			}
		} else
		if(swapri<=0 && rp->p_stat==SRUN && rp->p_time>inage) {
			p = rp;
			inage = rp->p_time;
		}
	}
	spl0();
	/*
	 * Swap found user out if sleeping,
	 * or if he has spent at least 4 seconds in core and
	 * the swapped-out process has spent at 2 seconds out.
	 * Otherwise wait a bit and try again.







Jun 19 11:27 1978  slp.c Page 5


	 */
	if (swapri>0 || (outage>=2 && inage>=4)) {
		p->p_flag =& ~SLOAD;
		xswap(p, 1, 0);
		goto loop;
	}
	spl6();
	runin++;
	sleep(&runin, PSWP);
	goto loop;

}

/*
 * Swap a process in.
 * Allocate data and possible text separately.
 * It would be better to do largest first.
 */
swapin(pp)
struct proc *pp;
{
	register struct proc *p;
	register struct text *xp;
	register int a;
	int x;

	p = pp;
	if ((a = malloc(coremap, p->p_size)) == NULL)
		return(0);
	if (xp = p->p_textp) {
		xlock(xp);
		if (xp->x_ccount==0) {
			if ((x = malloc(coremap, xp->x_size)) == NULL) {
				xunlock(xp);
				mfree(coremap, p->p_size, a);
				return(0);
			}
			xp->x_caddr = x;
			if ((xp->x_flag&XLOAD)==0)
				swap(xp->x_daddr,x,xp->x_size,B_READ);
		}
		xp->x_ccount++;
		xunlock(xp);
	}
	swap(p->p_addr, a, p->p_size, B_READ);
	mfree(swapmap, ctob(p->p_size), p->p_addr);
	p->p_addr = a;
	p->p_flag =| SLOAD;
	p->p_time = 0;
	return(1);
}

qswtch()
{

	setrq(u.u_procp);







Jun 19 11:27 1978  slp.c Page 6


	swtch();
}

/*
 * This routine is called to reschedule the CPU.
 * if the calling process is not in RUN state,
 * arrangements for it to restart must have
 * been made elsewhere, usually by calling via sleep.
 */
swtch()
{
	register n;
	register struct proc *p, *q;
	static struct proc *pp, *pq;

	/*
	 * Remember stack of caller
	 * and switch to schedulers stack.
	 */
	savu(u.u_rsav);
	retu(proc[0].p_addr);

loop:
	spl6();
	runrun = 0;
	pp = NULL;
	q = NULL;
	n = 128;
	/*
	 * Search for highest-priority runnable process
	 */
	for(p=runq; p!=NULL; p=p->p_link) {
		if((p->p_stat==SRUN) && (p->p_flag&SLOAD)) {
			if(p->p_pri <= n) {
				pp = p;
				pq = q;
				n = p->p_pri;
			}
		}
		q = p;
	}
	/*
	 * If no process is runnable, idle.
	 */
	p = pp;
	if(p == NULL) {
		idle();
		spl0();
		goto loop;
	}
	q = pq;
	if(q == NULL)
		runq = p->p_link; else
		q->p_link = p->p_link;
	curpri = n;
	spl0();







Jun 19 11:27 1978  slp.c Page 7


	/*
	 * Switch to stack of the new process and set up
	 * his segmentation registers.
	 */
	retu(p->p_addr);
	sureg();
	/*
	 * If the new process paused because it was
	 * swapped out, set the stack level to the last call
	 * to savu(u_ssav).  This means that the return
	 * which is executed immediately after the call to aretu
	 * actually returns from the last routine which did
	 * the savu.
	 */
	if(p->p_flag&SSWAP) {
		p->p_flag =& ~SSWAP;
		aretu(u.u_ssav);
	}
	/*
	 * The value returned here has many subtle implications.
	 * See the newproc comments.
	 */
	return(1);
}

/*
 * Create a new process-- the internal version of
 * sys fork.
 * It returns 1 in the new process.
 * How this happens is rather hard to understand.
 * The essential fact is that the new process is created
 * in such a way that appears to have started executing
 * in the same call to newproc as the parent;
 * but in fact the code that runs is that of swtch.
 * The subtle implication of the returned value of swtch
 * (see above) is that this is the value that newproc's
 * caller in the new process sees.
 */
newproc()
{
	int a1, a2;
	struct proc *p, *up;
	register struct proc *rpp;
	register *rip, n;
	struct proc *pend;

	p = NULL;
	/*
	 * First, just locate a slot for a process
	 * and copy the useful info from this process into it.
	 * The panic "cannot happen" because fork has already
	 * checked for the existence of a slot.
	 */
retry:
	mpid++;
	if(mpid < 0) {







Jun 19 11:27 1978  slp.c Page 8


		mpid = 0;
		goto retry;
	}
	for(rpp = &proc[0]; rpp < &proc[v.v_proc]; rpp++) {
		if(rpp->p_stat == NULL) {
			if(p == NULL)
				p = rpp;
		} else
			pend = rpp;
		if (rpp->p_pid==mpid || rpp->p_pgrp==mpid)
			goto retry;
	}
	if ((rpp = p)==NULL)
		panic("no procs");
	if (rpp > pend)
		pend = rpp;
	pend++;
	v.ve_proc = pend;

	/*
	 * make proc entry for new proc
	 */

	rip = u.u_procp;
	up = rip;
	rpp->p_stat = SRUN;
	rpp->p_clktim = 0;
	rpp->p_flag = SLOAD;
	rpp->p_uid = rip->p_uid;
	rpp->p_pgrp = rip->p_pgrp;
	rpp->p_nice = rip->p_nice;
	rpp->p_textp = rip->p_textp;
	rpp->p_pid = mpid;
	rpp->p_ppid = rip->p_pid;
	rpp->p_time = 0;
	rpp->p_cpu = 0;

	/*
	 * make duplicate entries
	 * where needed
	 */

	for(rip = &u.u_ofile[0]; rip < &u.u_ofile[NOFILE];)
		if((rpp = *rip++) != NULL)
			rpp->f_count++;
	if((rpp=up->p_textp) != NULL) {
		rpp->x_count++;
		rpp->x_ccount++;
	}
	u.u_cdir->i_count++;
	/*
	 * Partially simulate the environment
	 * of the new process so that when it is actually
	 * created (by copying) it will look right.
	 */
	savu(u.u_rsav);







Jun 19 11:27 1978  slp.c Page 9


	rpp = p;
	u.u_procp = rpp;
	rip = up;
	n = rip->p_size;
	a1 = rip->p_addr;
	rpp->p_size = n;
	a2 = malloc(coremap, n);
	/*
	 * If there is not enough core for the
	 * new process, swap out the current process to generate the
	 * copy.
	 */
	if(a2 == NULL) {
		rip->p_stat = SIDL;
		rpp->p_addr = a1;
		savu(u.u_ssav);
		xswap(rpp, 0, 0);
		rpp->p_flag =| SSWAP;
		rip->p_stat = SRUN;
	} else {
	/*
	 * There is core, so just copy.
	 */
		rpp->p_addr = a2;
		while(n--)
			copyseg(a1++, a2++);
	}
	u.u_procp = rip;
	setrq(rpp);
	return(0);
}

/*
 * Change the size of the data+stack regions of the process.
 * If the size is shrinking, it's easy-- just release the extra core.
 * If it's growing, and there is core, just allocate it
 * and copy the image, taking care to reset registers to account
 * for the fact that the system's stack has moved.
 * If there is no core, arrange for the process to be swapped
 * out after adjusting the size requirement-- when it comes
 * in, enough core will be allocated.
 * Because of the ssave and SSWAP flags, control will
 * resume after the swap in swtch, which executes the return
 * from this stack level.
 *
 * After the expansion, the caller will take care of copying
 * the user's stack towards or away from the data area.
 */
expand(newsize)
{
	int i, n;
	register *p, a1, a2;

	p = u.u_procp;
	n = p->p_size;
	p->p_size = newsize;







Jun 19 11:27 1978  slp.c Page 10


	a1 = p->p_addr;
	if(n >= newsize) {
		mfree(coremap, n-newsize, a1+newsize);
		return;
	}
	savu(u.u_rsav);
	a2 = malloc(coremap, newsize);
	if(a2 == NULL) {
		savu(u.u_ssav);
		xswap(p, 1, n);
		p->p_flag =| SSWAP;
		qswtch();
		/* no return */
	}
	p->p_addr = a2;
	for(i=0; i<n; i++)
		copyseg(a1+i, a2++);
	mfree(coremap, n, a1);
	retu(p->p_addr);
	sureg();
}










































Jun 19 11:27 1978  subr.c Page 1


#
#include "../hd/param.h"
#include "../hd/inode.h"
#include "../hd/user.h"
#include "../hd/buf.h"
#include "../hd/systm.h"

/*
 * Bmap defines the structure of file system storage
 * by returning the physical block number on a device given the
 * inode and the logical block number in a file.
 * When convenient, it also leaves the physical
 * block number of the next block of the file in rablock
 * for use in read-ahead.
 */
bmap(ip, bn)
struct inode *ip;
int bn;
{
	register *bp, *bap, nb;
	int *nbp, d, i;

	d = ip->i_dev;
	if(bn & ~03777) {
		u.u_error = EFBIG;
		return(0);
	}

	if((ip->i_mode&ILARG) == 0) {

		/*
		 * small file algorithm
		 */

		if((bn & ~7) != 0) {

			/*
			 * convert small to large
			 */

			if ((bp = alloc(d)) == NULL)
				return(NULL);
			bap = bp->b_addr;
			for(i=0; i<8; i++) {
				*bap++ = ip->i_addr[i];
				ip->i_addr[i] = 0;
			}
			ip->i_addr[0] = bp->b_blkno;
			bdwrite(bp);
			ip->i_mode =| ILARG;
			ip->i_flag =| IUPD;
			goto large;
		}
		nb = ip->i_addr[bn];
		if(nb == 0 && (bp = alloc(d)) != NULL) {
			bdwrite(bp);







Jun 19 11:27 1978  subr.c Page 2


			nb = bp->b_blkno;
			ip->i_addr[bn] = nb;
			ip->i_flag =| IUPD;
		}
		rablock = 0;
		if (bn<7)
			rablock = ip->i_addr[bn+1];
		return(nb);
	}

	/*
	 * large file algorithm
	 */

    large:
	i = bn>>8;
	if((nb=ip->i_addr[i]) == 0) {
		if ((bp = alloc(d)) == NULL)
			return(NULL);
		ip->i_addr[i] = bp->b_blkno;
		ip->i_flag =| IUPD;
	} else
		bp = bread(d, nb);
	bap = bp->b_addr;

	/*
	 * normal indirect fetch
	 */

	i = bn & 0377;
	if((nb=bap[i]) == 0 && (nbp = alloc(d)) != NULL) {
		nb = nbp->b_blkno;
		bap[i] = nb;
		bdwrite(nbp);
		bdwrite(bp);
	} else
		brelse(bp);
	rablock = 0;
	if(i < 255)
		rablock = bap[i+1];
	return(nb);
}

/*
 * Pass back  c  to the user at his location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * on the last character of the user's read.
 * u_base is in the user address space unless u_segflg is set.
 */
passc(c)
char c;
{
	register id;

	if((id = u.u_segflg) == 1)
		*u.u_base = c;







Jun 19 11:27 1978  subr.c Page 3


	else
		if(id?suibyte(u.u_base, c):subyte(u.u_base, c) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(u.u_count == 0? -1: 0);
}

/*
 * Pick up and return the next character from the user's
 * write call at location u_base;
 * update u_base, u_count, and u_offset.  Return -1
 * when u_count is exhausted.  u_base is in the user's
 * address space unless u_segflg is set.
 */
cpass()
{
	register c, id;

	if(u.u_count == 0)
		return(-1);
	if((id = u.u_segflg) == 1)
		c = *u.u_base;
	else
		if((c = id==0?fubyte(u.u_base):fuibyte(u.u_base)) < 0) {
			u.u_error = EFAULT;
			return(-1);
		}
	u.u_count--;
	if(++u.u_offset[1] == 0)
		u.u_offset[0]++;
	u.u_base++;
	return(c&0377);
}

/*
 * Routine which sets a user error; placed in
 * illegal entries in the bdevsw and cdevsw tables.
 */
nodev()
{

	u.u_error = ENODEV;
}

/*
 * Null routine; placed in insignificant entries
 * in the bdevsw and cdevsw tables.
 */
nulldev()
{
}







Jun 19 11:27 1978  subr.c Page 4



/*
 * copy count words from from to to.
 */
bcopy(from, to, count)
int *from, *to;
{
	register *a, *b, c;

	a = from;
	b = to;
	c = count;
	do
		*b++ = *a++;
	while(--c);
}















































Jun 19 11:27 1978  sys1.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/proc.h"
#include "../hd/buf.h"
#include "../hd/reg.h"
#include "../hd/inode.h"
#include "../hd/seg.h"
#include "../hd/var.h"

exec()
{
	register nc;
	register char *cp;
	register struct buf *bp;
	int na, bno, ucp, ap, c, ip;

	if((ip = gethead()) == NULL)
		return;
	bp = na = nc = 0;
	/* collect arglist */
	if ((bno = malloc(swapmap,(NCARGS+511)/512)) == 0)
		panic("Out of swap");
	if (u.u_arg[1]) while(ap = fuword(u.u_arg[1])) {
		na++;
		if(ap == -1)
			u.u_error = EFAULT;
		u.u_arg[1] =+ 2;
		do {
			if (nc >= NCARGS-1)
				u.u_error = E2BIG;
			if ((c = fubyte(ap++)) < 0)
				u.u_error = EFAULT;
			if (u.u_error)
				goto bad;
			if ((nc&0777) == 0) {
				if (bp)
					bawrite(bp);
				bp = getblk(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			nc++;
			*cp++ = c;
		} while (c>0);
	}
	if (bp)
		bawrite(bp);
	bp = 0;
	if((nc&1) != 0)
		nc++;
	ip = getxfile(ip, nc+2*na);
	if (u.u_error)
		goto bad;
	/* copy back arglist */
	ucp = -nc;







Jun 19 11:27 1978  sys1.c Page 2


	ap = ucp - na*2 - 4;
	u.u_ar0[R6] = ap;
	suword(ap, na);
	nc = 0;
	while(na--) {
		suword(ap=+2, ucp);
		do {
			if ((nc&0777) == 0) {
				if (bp)
					brelse(bp);
				bp = bread(swapdev, bno+(nc>>9));
				cp = bp->b_addr;
			}
			subyte(ucp++, (c = *cp++));
			nc++;
		} while(c&0377);
	}
	suword(ap+2, -1);
	setregs();
bad:
	if (bp)
		brelse(bp);
	if(ip)
		iput(ip);
	mfree(swapmap, (NCARGS+511)/512, bno);
}

/*
 * Read in and set up memory for executed file.
 */
getxfile(ip,nargc)
register struct inode *ip;
{
	register i, as, ds;

	u.u_prof[3] = 0;
	xfree();
	as = nargc>>6;
	u.u_ssize = SSIZE+as;
	u.u_dsize = ((u.u_exdata.ux_dsize+u.u_exdata.ux_bsize+63)>>6) & 01777;
	u.u_tsize = ((u.u_exdata.ux_tsize+63)>>6) & 01777;
	i = USIZE+u.u_dsize+u.u_ssize;
	expand(i);
	i =- as;
	ds = USIZE+((u.u_exdata.ux_dsize>>6)&01777);
	while(--i >= ds)
		clearseg(u.u_procp->p_addr+i);
	xalloc(ip);
	/* read in data segment */
	estabur(0, u.u_dsize, 0, 0, RO);
	u.u_base = 0;
	u.u_offset[1] = 020+u.u_exdata.ux_tsize;
	u.u_count = u.u_exdata.ux_dsize;
	readi(ip);
	if (u.u_count!=0)
		u.u_error = EFAULT;







Jun 19 11:27 1978  sys1.c Page 3


	/*
	 * set SUID/SGID protections, if no tracing
	 */
	if ((u.u_procp->p_flag&STRC)==0) {
		if(ip->i_mode&ISUID)
			if(u.u_uid != 0) {
				u.u_uid = ip->i_uid;
				u.u_procp->p_uid = ip->i_uid;
			}
		if(ip->i_mode&ISGID)
			u.u_gid = ip->i_gid;
	}
	u.u_sep = (u.u_exdata.ux_mag == 0411)?1:0;
	estabur(u.u_tsize, u.u_dsize, u.u_ssize,u.u_sep,RO);
	iput(ip);
	if (u.u_error)
		psignal(u.u_procp, SIGKIL);
	return(0);
}


gethead()
{
	register struct inode *ip;
	register sep, ts;
	long	ls;
	int	ds;
	extern int uchar();

	if ((ip = namei(uchar, 0)) == NULL)
		return(NULL);
	if (access(ip, IEXEC) ||
	   (ip->i_mode & IFMT) != 0 ||
	   (ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
		u.u_error = EACCES;
		goto bad;
	}
	/*
	 * read in first few bytes of file for segment sizes
	 * ux_mag = 407/410/411
	 *  407 is plain executable
	 *  410 is RO text
	 *  411 is separated ID
	 */
	u.u_base = &u.u_exdata;
	u.u_count = sizeof(u.u_exdata);
	u.u_offset[0] = u.u_offset[1] = 0;
	u.u_segflg = 1;
	readi(ip);
	u.u_segflg = 0;
	if(u.u_error)
		goto bad;
	if (u.u_count!=0) {
		u.u_error = ENOEXEC;
		goto bad;
	}







Jun 19 11:27 1978  sys1.c Page 4


	sep = 0;
	ls = 63;
	dpadd(&ls, u.u_exdata.ux_dsize);
	dpadd(&ls, u.u_exdata.ux_bsize);
	if(u.u_exdata.ux_mag == 0407) {
		dpadd(&ls, u.u_exdata.ux_tsize);
		u.u_exdata.ux_dsize =+ u.u_exdata.ux_tsize;
		u.u_exdata.ux_tsize = 0;
	} else if (u.u_exdata.ux_mag == 0411)
		sep++;
	else if (u.u_exdata.ux_mag != 0410) {
		u.u_error = ENOEXEC;
		goto bad;
	}
	if(u.u_exdata.ux_tsize!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
		u.u_error = ETXTBSY;
		goto bad;
	}
	ts = (u.u_exdata.ux_tsize>>6) & 01777;
	if (u.u_exdata.ux_tsize&077)
		ts++;
	ds = ls>>6;
	if(checkur(ts,ds,SSIZE,sep)==0)
		return(ip);
bad:
	iput(ip);
	return(NULL);
}

setregs()
{
	register int *rp;
	register char *cp;

	for(rp = &u.u_signal[0]; rp < &u.u_signal[NSIG]; rp++)
		if((*rp & 1) == 0)
			*rp = 0;
	for(cp = &regloc[0]; cp < &regloc[6];)
		u.u_ar0[*cp++] = 0;
	u.u_ar0[R7] = u.u_exdata.ux_entloc & ~01;
	for(rp = &u.u_fsav[0]; rp < &u.u_fsav[25];)
		*rp++ = 0;

}

/*
 * exit system call:
 * pass back caller's r0
 */
rexit()
{

	u.u_arg[0] = u.u_ar0[R0] << 8;
	exit();
}








Jun 19 11:27 1978  sys1.c Page 5


/*
 * Release resources.
 * Save u. area for parent to look at.
 * Enter zombie state.
 * Wake up parent and init processes,
 * and dispose of children.
 */
exit()
{
	register int *a;
	register struct proc *p, *q;

	p = u.u_procp;
	p->p_flag =& ~STRC;
	p->p_clktim = 0;
	for(a = &u.u_signal[0]; a < &u.u_signal[NSIG];)
		*a++ = 1;
	for(a = &u.u_ofile[0]; a < &u.u_ofile[NOFILE]; a++)
		if (*a) {
			closef(*a);
			*a = NULL;
		}
	plock(u.u_cdir);
	iput(u.u_cdir);
	xfree();
	mfree(coremap, p->p_size, p->p_addr);
	p->p_stat = SZOMB;
	p->xp_xstat = u.u_arg[0];
	p->xp_utime = u.u_cutime + u.u_utime;
	p->xp_stime = u.u_cstime + u.u_stime;
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(q->p_ppid == p->p_pid) {
			wakeup(&proc[1]);
			q->p_ppid = 1;
			if (q->p_stat==SSTOP)
				setrun(q);
		}
	for(q = &proc[0]; q < v.ve_proc; q++)
		if(p->p_ppid == q->p_pid) {
			wakeup(q);
			swtch();
			/* no return */
		}
	printf("Init proc dead");
	swtch();
}

/*
 * Wait system call.
 * Search for a terminated (zombie) child,
 * finally lay it to rest, and collect its status.
 * Look also for stopped (traced) children,
 * and pass back status from them.
 */
wait()
{







Jun 19 11:27 1978  sys1.c Page 6


	register f;
	register struct proc *p;

	f = 0;

loop:
	for(p = &proc[0]; p < v.ve_proc; p++)
	if(p->p_ppid == u.u_procp->p_pid) {
		f++;
		if(p->p_stat == SZOMB) {
			u.u_ar0[R0] = p->p_pid;
			u.u_ar0[R1] = p->xp_xstat;
			u.u_cutime =+ p->xp_utime;
			u.u_cstime =+ p->xp_stime;
			p->p_stat = NULL;
			p->p_pid = 0;
			p->p_ppid = 0;
			p->p_sig = 0;
			p->p_pgrp = 0;
			p->p_flag = 0;
			p->p_wchan = 0;
			return;
		}
		if(p->p_stat == SSTOP) {
			if((p->p_flag&SWTED) == 0) {
				p->p_flag =| SWTED;
				u.u_ar0[R0] = p->p_pid;
				u.u_ar0[R1] = (fsig(p)<<8) | 0177;
				return;
			}
			continue;
		}
	}
	if(f) {
		sleep(u.u_procp, PWAIT);
		goto loop;
	}
	u.u_error = ECHILD;
}

/*
 * fork system call.
 */
fork()
{
	register struct proc *p1, *p2;
	register a;

	/*
	 * Make sure there's enough swap space for max
	 * core image, thus reducing chances of running out
	 */
	if ((a = malloc(swapmap, ctob(MAXMEM))) == 0) {
		u.u_error = ENOMEM;
		goto out;
	}







Jun 19 11:27 1978  sys1.c Page 7


	mfree(swapmap, ctob(MAXMEM), a);
	p1 = u.u_procp;
	for(p2 = &proc[0]; p2 < &proc[v.v_proc]; p2++)
		if(p2->p_stat == NULL)
			goto found;
	u.u_error = EAGAIN;
	goto out;

found:
	if(newproc()) {
		u.u_ar0[R0] = p1->p_pid;
		u.u_cstime = 0;
		u.u_stime = 0;
		u.u_cutime = 0;
		u.u_utime = 0;
		return;
	}
	u.u_ar0[R0] = p2->p_pid;

out:
	u.u_ar0[R7] =+ 2;
}

/*
 * break system call.
 *  -- bad planning: "break" is a dirty word in C.
 */
sbreak()
{
	register a, n, d;
	int i;

	/*
	 * set n to new data size
	 * set d to new-old
	 * set n to new total size
	 */

	n = (((u.u_arg[0]+63)>>6) & 01777);
	if(!u.u_sep)
		n =- ctos(u.u_tsize) * 128;
	if(n < 0)
		n = 0;
	d = n - u.u_dsize;
	n =+ USIZE+u.u_ssize;
	if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep, RO))
		return;
	u.u_dsize =+ d;
	if(d > 0)
		goto bigger;
	a = u.u_procp->p_addr + n - u.u_ssize;
	i = n;
	n = u.u_ssize;
	while(n--) {
		copyseg(a-d, a);
		a++;







Jun 19 11:27 1978  sys1.c Page 8


	}
	expand(i);
	return;

bigger:
	expand(n);
	a = u.u_procp->p_addr + n;
	n = u.u_ssize;
	while(n--) {
		a--;
		copyseg(a-d, a);
	}
	while(d--)
		clearseg(--a);
}
















































Jun 19 11:27 1978  sys2.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/user.h"
#include "../hd/reg.h"
#include "../hd/file.h"
#include "../hd/inode.h"

/*
 * read system call
 */
read()
{
	rdwr(FREAD);
}

/*
 * write system call
 */
write()
{
	rdwr(FWRITE);
}

/*
 * common code for read and write calls:
 * check permissions, set base, count, and offset,
 * and switch out to readi, writei, or pipe code.
 */
rdwr(mode)
{
	register *fp, *ip, m;

	m = mode;
	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if((fp->f_flag&m) == 0) {
		u.u_error = EBADF;
		return;
	}
	u.u_base = u.u_arg[0];
	u.u_count = u.u_arg[1];
	u.u_segflg = 0;
	if(fp->f_flag&FPIPE) {
		if(m==FREAD)
			readp(fp); else
			writep(fp);
	} else {
		ip = fp->f_inode;
		u.u_offset[1] = fp->f_offset[1];
		u.u_offset[0] = fp->f_offset[0];
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			plock(ip);
		if(m==FREAD)
			readi(ip); else







Jun 19 11:27 1978  sys2.c Page 2


			writei(ip);
		if((ip->i_mode&(IFCHR&IFBLK)) == 0)
			prele(ip);
		dpadd(fp->f_offset, u.u_arg[1]-u.u_count);
	}
	u.u_ar0[R0] = u.u_arg[1]-u.u_count;
}

/*
 * open system call
 */
open()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	u.u_arg[1]++;
	open1(ip, u.u_arg[1], 0);
}

/*
 * creat system call
 */
creat()
{
	register *ip;
	extern uchar;

	ip = namei(&uchar, 1);
	if(ip == NULL) {
		if(u.u_error)
			return;
		ip = maknode(u.u_arg[1]&07777&(~ISVTX));
		if (ip==NULL)
			return;
		open1(ip, FWRITE, 2);
	} else
		open1(ip, FWRITE, 1);
}

/*
 * common code for open and creat.
 * Check permissions, allocate an open file structure,
 * and call the device open routine if any.
 */
open1(ip, mode, trf)
int *ip;
{
	register struct file *fp;
	register *rip, m;
	int i;

	rip = ip;







Jun 19 11:27 1978  sys2.c Page 3


	m = mode;
	if(trf != 2) {
		if(m&FREAD)
			access(rip, IREAD);
		if(m&FWRITE) {
			access(rip, IWRITE);
			if((rip->i_mode&IFMT) == IFDIR)
				u.u_error = EISDIR;
		}
	}
	if(u.u_error)
		goto out;
	if(trf == 1)
		itrunc(rip);
	prele(rip);
	if ((fp = falloc()) == NULL)
		goto out;
	fp->f_flag = m&(FREAD|FWRITE);
	fp->f_inode = rip;
	i = u.u_ar0[R0];
	if (rip->i_mode&(IFCHR&IFBLK))
		openi(rip, m&FWRITE);
	if(u.u_error == 0)
		return;
	u.u_ofile[i] = NULL;
	fp->f_count--;

out:
	iput(rip);
}

/*
 * close system call
 */
close()
{
	register *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	u.u_ofile[u.u_ar0[R0]] = NULL;
	closef(fp);
}

/*
 * seek system call
 */
seek()
{
	int n[2];
	register *fp, t;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;







Jun 19 11:27 1978  sys2.c Page 4


	if(fp->f_flag&FPIPE) {
		u.u_error = ESPIPE;
		return;
	}
	t = u.u_arg[1];
	if(t > 2) {
		n[1] = u.u_arg[0]<<9;
		n[0] = u.u_arg[0]>>7;
		if(t == 3)
			n[0] =& 0777;
	} else {
		n[1] = u.u_arg[0];
		n[0] = 0;
		if(t!=0 && n[1]<0)
			n[0] = -1;
	}
	switch(t) {

	case 1:
	case 4:
		n[0] =+ fp->f_offset[0];
		dpadd(n, fp->f_offset[1]);
		break;

	default:
		n[0] =+ fp->f_inode->i_size0&0377;
		dpadd(n, fp->f_inode->i_size1);

	case 0:
	case 3:
		;
	}
	if (n[0] & ~0777)
		u.u_error = EFBIG;
	else {
		fp->f_offset[1] = n[1];
		fp->f_offset[0] = n[0];
	}
}

/*
 * Tell -- discover offset of file R/W pointer
 */
tell()
{
	register struct file *fp;

	if (fp = getf(u.u_ar0[R0])) {
		u.u_ar0[R0] = fp->f_offset[0];
		u.u_ar0[R1] = fp->f_offset[1];
	}
}

/*
 * link system call
 */







Jun 19 11:27 1978  sys2.c Page 5


link()
{
	register *ip, *xp;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	if(ip->i_nlink >= 127) {
		u.u_error = EMLINK;
		goto out;
	}
	if((ip->i_mode&IFMT)==IFDIR && !suser())
		goto out;
	/*
	 * Unlock to avoid possibly hanging the namei.
	 * Sadly, this means races. (Suppose someone
	 * deletes the file in the meantime?)
	 * Nor can it be locked again later
	 * because then there will be deadly
	 * embraces.
	 */
	prele(ip);
	u.u_dirp = u.u_arg[1];
	xp = namei(&uchar, 1);
	if(xp != NULL) {
		u.u_error = EEXIST;
		iput(xp);
	}
	if(u.u_error)
		goto out;
	if(u.u_pdir->i_dev != ip->i_dev) {
		iput(u.u_pdir);
		u.u_error = EXDEV;
		goto out;
	}
	wdir(ip);
	ip->i_nlink++;
	ip->i_flag =| IUPD;

out:
	iput(ip);
}

/*
 * mknod system call
 */
mknod()
{
	register *ip;
	extern uchar;

	if(suser()) {
		ip = namei(&uchar, 1);
		if(ip != NULL) {
			u.u_error = EEXIST;







Jun 19 11:27 1978  sys2.c Page 6


			goto out;
		}
	}
	if(u.u_error)
		return;
	ip = maknode(u.u_arg[1]);
	if (ip==NULL)
		return;
	ip->i_addr[0] = u.u_arg[2];

out:
	iput(ip);
}

/*
 * sleep system call
 * not to be confused with the sleep internal routine.
 */
sslep()
{
	long d;

	spl7();
	d = time + u.u_ar0[R0];
	while (time < d) {
		if (tout<=time || d<tout)
			tout = d;
		sleep(&tout, PSLEP);
	}
	spl0();
}

/*
 * access system call
 */
saccess()
{
	extern uchar;
	register svuid, svgid;
	register *ip;

	svuid = u.u_uid;
	svgid = u.u_gid;
	u.u_uid = u.u_ruid;
	u.u_gid = u.u_rgid;
	ip = namei(&uchar, 0);
	if (ip != NULL) {
		if (u.u_arg[1]&(IREAD>>6))
			access(ip, IREAD);
		if (u.u_arg[1]&(IWRITE>>6))
			access(ip, IWRITE);
		if (u.u_arg[1]&(IEXEC>>6))
			access(ip, IEXEC);
		iput(ip);
	}
	u.u_uid = svuid;







Jun 19 11:27 1978  sys2.c Page 7


	u.u_gid = svgid;
}





























































Jun 19 11:27 1978  sys3.c Page 1


#
#include "../hd/param.h"
#include "../hd/systm.h"
#include "../hd/reg.h"
#include "../hd/buf.h"
#include "../hd/filsys.h"
#include "../hd/user.h"
#include "../hd/inode.h"
#include "../hd/file.h"
#include "../hd/conf.h"
#include "../hd/var.h"

/*
 * the fstat system call.
 */
fstat()
{
	register *fp, *base;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	base	= u.u_arg[0];
	stat1(fp->f_inode, base);
	if (fp->f_flag&FPIPE)		/* correct if pipe */
		suword(&base[5],fp->f_inode->i_size1-fp->f_offset[1]);
}

/*
 * the stat system call.
 */
stat()
{
	register ip;
	extern uchar;

	ip = namei(&uchar, 0);
	if(ip == NULL)
		return;
	stat1(ip, u.u_arg[1]);
	iput(ip);
}

/*
 * The basic routine for fstat and stat:
 * get the inode and pass appropriate parts back.
 */
stat1(ip, ub)
int *ip;
{
	register i, *bp, *cp;

	iupdat(ip);
	bp = bread(ip->i_dev, ldiv(ip->i_number+31, 16));
	cp = bp->b_addr + 32*lrem(ip->i_number+31, 16) + 24;
	ip = &(ip->i_dev);







Jun 19 11:27 1978  sys3.c Page 2


	for(i=0; i<14; i++) {
		if (suword(ub, *ip) != *ip++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	for(i=0; i<4; i++) {
		if (suword(ub, *cp) != *cp++)
			u.u_error = EFAULT;
		ub =+ 2;
	}
	brelse(bp);
}

/*
 * the dup system call.
 */
dup()
{
	register i, *fp;

	fp = getf(u.u_ar0[R0]);
	if(fp == NULL)
		return;
	if ((i = ufalloc()) < 0)
		return;
	u.u_ofile[i] = fp;
	fp->f_count++;
}

/*
 * the mount system