~kris/9p

9hist

9f49db2a6bc926f6777d3faf6d4c2facfc8bcacb — David du Colombier 35 years ago a0a8ac2
Plan 9 from Bell Labs 1990-11-10
M gnot/chan.c => gnot/chan.c +1 -0
@@ 80,6 80,7 @@ loop:
		c->flag = 0;
		c->ref = 1;
		unlock(&chanalloc);
		c->dev = 0;
		c->offset = 0;
		c->mnt = 0;
		c->stream = 0;

M gnot/dat.h => gnot/dat.h +1 -0
@@ 152,6 152,7 @@ struct Conf
	int	nasync;		/* number of async protocol modules */
	int	npipe;		/* number of pipes */
	int	nservice;	/* number of services */
	int	nfsyschan;	/* number of filsys open channels */
};

struct Dev

M gnot/devsrv.c => gnot/devsrv.c +72 -62
@@ 7,21 7,22 @@
#include	"devtab.h"
#include	"fcall.h"

void *calloc(unsigned int, unsigned int);
void *calloc(unsigned, unsigned);
void free(void *);

/* This structure holds the contents of a directory entry.  Entries are kept
 * in a linked list.
 */
struct entry {
typedef struct Entry Entry;
struct Entry {
	Lock;
	struct entry *next;	/* next entry */
	struct entry **back;	/* entry pointer */
	struct entry *parent;	/* parent directory */
	Entry *next;		/* next entry */
	Entry **back;		/* entry pointer */
	Entry *parent;		/* parent directory */
	Dir dir;		/* dir structure */
	union {
		Chan *chan;		/* if not a subdirectory */
		struct entry *entries;	/* directory entries */
	union{
		Chan *chan;	/* if not a subdirectory */
		Entry *entries;	/* directory entries */
	};
};



@@ 35,11 36,13 @@ srvreset(void)
{
}

struct entry *srv_alloc(int mode){
	struct entry *e = calloc(1, sizeof(*e));
Entry *
srvalloc(int mode){
	Entry *e;
	static Lock qidlock;
	static nextqid;

	e = calloc(1, sizeof(Entry));
	e->dir.atime = e->dir.mtime = seconds();
	lock(&qidlock);	/* for qid allocation */
	e->dir.qid = mode | nextqid++;


@@ 52,11 55,11 @@ srvattach(char *spec)
{
	Chan *c;
	static Lock rootlock;
	static struct entry *root;
	static Entry *root;

	lock(&rootlock);
	if (root == 0) {
		root = srv_alloc(CHDIR);
	if(root==0){
		root = srvalloc(CHDIR);
		root->dir.mode = CHDIR | 0777;
	}
	unlock(&rootlock);


@@ 77,23 80,23 @@ srvclone(Chan *c, Chan *nc)
int
srvwalk(Chan *c, char *name)
{
	struct entry *dir, *e;
	Entry *dir, *e;

	isdir(c);
	if (strcmp(name, ".") == 0)
	if(strcmp(name, ".") == 0)
		return 1;
	if ((dir = c->aux) == 0)
	if((dir=c->aux) == 0)
		panic("bad aux pointer in srvwalk");
	if (strcmp(name, "..") == 0)
	if(strcmp(name, "..") == 0)
		e = dir->parent;
	else {
	else{
		lock(dir);
		for (e = dir->entries; e != 0; e = e->next)
		for(e=dir->entries; e; e=e->next)
			if (strcmp(name, e->dir.name) == 0)
				break;
		unlock(dir);
	}
	if (e == 0) {
	if(e==0){
		u->error.code = Enonexist;
		u->error.type = 0;
		u->error.dev = 0;


@@ 107,32 110,33 @@ srvwalk(Chan *c, char *name)
void
srvstat(Chan *c, char *db)
{
	struct entry *e = c->aux;
	Entry *e;

	e = c->aux;
	convD2M(&e->dir, db);
}

Chan *
srvopen(Chan *c, int omode)
{
	struct entry *e;
	Entry *e;
	Chan *f;

	if (c->qid & CHDIR) {
		if (omode != OREAD)
	if(c->qid & CHDIR){
		if(omode != OREAD)
			error(0, Eisdir);
		c->mode = omode;
		c->flag |= COPEN;
		c->offset = 0;
		return c;
	}
	if ((e = c->aux) == 0)
		panic("bad aux pointer in srvopen");
	if ((f = e->chan) == 0)
	if((e=c->aux) == 0)
		error(0, Egreg);
	if((f=e->chan) == 0)
		error(0, Eshutdown);
	if (omode & OTRUNC)
	if(omode & OTRUNC)
		error(0, Eperm);
	if (omode != f->mode && f->mode != ORDWR)
	if(omode!=f->mode && f->mode!=ORDWR)
		error(0, Eperm);
	close(c);
	incref(f);


@@ 142,25 146,27 @@ srvopen(Chan *c, int omode)
void
srvcreate(Chan *c, char *name, int omode, ulong perm)
{
	struct entry *parent = c->aux, *e;
	Entry *parent, *e;

	parent = c->aux;
	isdir(c);
	lock(parent);
	if (waserror()) {
	if (waserror()){
		unlock(parent);
		nexterror();
	}
	for (e = parent->entries; e != 0; e = e->next)
		if (strcmp(name, e->dir.name) == 0)
	for(e=parent->entries; e; e=e->next)
		if(strcmp(name, e->dir.name) == 0)
			error(0, Einuse);
	e = srv_alloc(perm & CHDIR);
	e = srvalloc(perm & CHDIR);
	e->parent = parent;
	strcpy(e->dir.name, name);
	e->dir.mode = perm & parent->dir.mode;
	e->dir.gid = parent->dir.gid;
	if ((e->next = parent->entries) != 0)
	if(e->next = parent->entries)	/* assign = */
		e->next->back = &e->next;
	*(e->back = &parent->entries) = e;
	e->back = &parent->entries;
	*e->back = e;
	parent->dir.mtime = e->dir.mtime;
	unlock(parent);
	poperror();


@@ 173,25 179,25 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
void
srvremove(Chan *c)
{
	struct entry *e = c->aux;
	Entry *e;

	if (e->parent == 0)
	e = c->aux;
	if(e->parent == 0)
		error(0, Eperm);
	lock(e->parent);
	if (waserror()) {
	if(waserror()){
		unlock(e->parent);
		nexterror();
	}
	if (e->dir.mode & CHDIR) {
	if(e->dir.mode & CHDIR){
		if (e->entries != 0)
			error(0, Eperm);
	}
	else {
		if (e->chan == 0)
	}else{
		if(e->chan == 0)
			error(0, Eshutdown);
		close(e->chan);
	}
	if ((*e->back = e->next) != 0)
	if(*e->back = e->next)	/* assign = */
		e->next->back = e->back;
	unlock(e->parent);
	poperror();


@@ 213,11 219,13 @@ srvclose(Chan *c)
 * to a list of entries in this directory.  Count is the size to be
 * read.
 */
int srv_direntry(struct entry *e, char *a, long count){
int
srvdirentry(Entry *e, char *a, long count){
	Dir dir;
	int n = 0;
	int n;

	while (n != count && e != 0) {
	n = 0;
	while(n!=count && e!=0){
		n += convD2M(&e->dir, a + n);
		e = e->next;
	}


@@ 227,23 235,24 @@ int srv_direntry(struct entry *e, char *a, long count){
long
srvread(Chan *c, void *va, long n)
{
	struct entry *dir = c->aux, *e;
	int offset = c->offset;
	Entry *dir, *e;
	int offset;

	dir = c->aux;
	offset = c->offset;
	isdir(c);
	if (n <= 0)
	if(n <= 0)
		return 0;
	if ((offset % DIRLEN) != 0 || (n % DIRLEN) != 0)
		error(0, Egreg);
	if(offset%DIRLEN || n%DIRLEN)
		error(0, Ebaddirread);
	lock(dir);
	for (e = dir->entries; e != 0; e = e->next)
		if (offset <= 0) {
			n = srv_direntry(e, va, n);
	for(e=dir->entries; e; e=e->next)
		if(offset <= 0){
			n = srvdirentry(e, va, n);
			unlock(dir);
			c->offset += n;
			return n;
		}
		else
		}else
			offset -= DIRLEN;
	unlock(dir);
	return 0;


@@ 252,20 261,21 @@ srvread(Chan *c, void *va, long n)
long
srvwrite(Chan *c, void *va, long n)
{
	struct entry *e = c->aux;
	Entry *e;
	int i, fd;
	char buf[32];

	if (e->dir.mode & CHDIR)
	e = c->aux;
	if(e->dir.mode & CHDIR)
		panic("write to directory");
	lock(e);
	if (waserror()) {
	if(waserror()){
		unlock(e);
		nexterror();
	}
	if (e->chan != 0)
	if(e->chan)
		error(0, Egreg);
	if (n >= sizeof buf)
	if(n >= sizeof buf)
		error(0, Egreg);
	memcpy(buf, va, n);	/* so we can NUL-terminate */
	buf[n] = 0;

M gnot/errno.h => gnot/errno.h +1 -0
@@ 58,5 58,6 @@ enum{
	Enovmem,	/* virtual memory allocation failed */
	Enoasync,	/* out of async stream modules */
	Enopipe,	/* out of pipes */
	Enofilsys,	/* out of filsys resources */
	Egreg,		/* ken hasn't implemented datakit */
};

M gnot/fault.c => gnot/fault.c +3 -1
@@ 166,6 166,8 @@ fault(Ureg *ur, FFrame *f)
				qunlock(o->chan);
				pg->o = 0;
				pg->ref--;
				if(user)
					pexit("Interrupt", 0);
				goto cant;
			}
			o->chan->offset = (addr-o->va) + o->minca;


@@ 290,7 292,7 @@ validaddr(ulong addr, ulong len, int write)
	if((long)len < 0){
    Err:
		pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
		postnote(u->p, 1, "bad address", NDebug);
		postnote(u->p, 1, "sys: bad address", NDebug);
		error(0, Ebadarg);
	}
    Again:

M gnot/fns.h => gnot/fns.h +2 -0
@@ 33,6 33,7 @@ int	devno(int, int);
Chan	*devopen(Chan*, int, Dirtab*, int, Devgen*);
void	devstat(Chan*, char*, Dirtab*, int, Devgen*);
int	devwalk(Chan*, char*, Dirtab*, int, Devgen*);
Chan	*domount(Chan*);
void	duartbaud(int);
void	duartbreak(int);
void	duartdtr(int);


@@ 50,6 51,7 @@ void	fault(Ureg*, FFrame*);
void	fdclose(int);
Chan	*fdtochan(int, int);
void	filsys(Chan*, char*, long);
void	filsysinit(void);
void	firmware(void);
void	flowctl(Queue*);
void	flushcpucache(void);

M gnot/main.c => gnot/main.c +2 -0
@@ 47,6 47,7 @@ main(void)
	chandevreset();
	streaminit();
	serviceinit();
	filsysinit();
	pageinit();
	kmapinit();
	userinit();


@@ 328,4 329,5 @@ confinit(void)
	conf.nasync = 1;
	conf.npipe = conf.nstream/2;
	conf.nservice = conf.nproc/5;
	conf.nfsyschan = 31 + conf.nchan/20;
}

M gnot/pgrp.c => gnot/pgrp.c +3 -0
@@ 116,6 116,7 @@ closepgrp(Pgrp *p)
	Envp *ep;

	if(decref(p) == 0){
		lock(&p->debug);
		p->pgrpid = -1;
		m = p->mtab;
		for(i=0; i<p->nmtab; i++,m++)


@@ 130,6 131,7 @@ closepgrp(Pgrp *p)
		lock(&pgrpalloc);
		p->next = pgrpalloc.free;
		pgrpalloc.free = p;
		unlock(&p->debug);
		unlock(&pgrpalloc);
	}
}


@@ 144,6 146,7 @@ loop:
	if(m = mountalloc.free){		/* assign = */
		mountalloc.free = m->next;
		m->ref = 1;
		m->next = 0;
		m->mountid = ++mountalloc.mountid;
		unlock(&mountalloc);
		return m;

M gnot/proc.c => gnot/proc.c +8 -3
@@ 135,7 135,7 @@ save(Balu *balu)
		m->fpstate = FPdirty;
	}
	if(BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(balu, BALU, sizeof *balu);
		memcpy(balu, BALU, sizeof(Balu));
	else{
		balu->cr0 = 0xFFFFFFFF;
		BALU->cr0 = 0xFFFFFFFF;


@@ 699,6 699,7 @@ Proc *
kproc(char *name, void (*func)(void *), void *arg)
{
	Proc *p;
	Chan *c;
	int n;
	ulong upa;
	int lastvar;	/* used to compute stack address */


@@ 730,8 731,12 @@ kproc(char *name, void (*func)(void *), void *arg)
	 */
	incref(up->dot);
	for(n=0; n<=up->maxfd; n++)
		up->fd[n] = 0;
	up->maxfd = 0;
		if(func)
			up->fd[n] = 0;
		else if(c = u->fd[n])		/* assign = */
			incref(c);
	if(!func)
		up->maxfd = 0;
	up->p = p;
	kunmap(k);


M gnot/stream.c => gnot/stream.c +4 -0
@@ 133,6 133,10 @@ allocb(ulong size)
	while(bcp->first == 0){
		unlock(bcp);
		qlock(bcp);
		if(waserror()){
			qunlock(bcp);
			nexterror();
		}
		tsleep(&bcp->r, isblock, (void *)bcp, 250);
		qunlock(bcp);
		lock(bcp);

M gnot/trap.c => gnot/trap.c +3 -3
@@ 91,7 91,7 @@ trap(Ureg *ur)
	if(u)
		u->p->pc = ur->pc;		/* BUG */
	if(user){
		sprint(buf, "pc=%lux trap: %s", ur->pc, excname(ur->vo));
		sprint(buf, "sys: trap: %s", ur->pc, excname(ur->vo));
		postnote(u->p, 1, buf, NDebug);
	}else{
		print("kernel trap vo=0x%ux pc=%lux\n", ur->vo, ur->pc);


@@ 271,14 271,14 @@ syscall(Ureg *aur)
	if(!waserror()){
		if(r0 >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", r0, ((Ureg*)UREGADDR)->pc);
			msg = "bad sys call";
			msg = "sys: bad sys call";
	    Bad:
			postnote(u->p, 1, msg, NDebug);
			error(0, Ebadarg);
		}
		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "odd stack";
			msg = "sys: odd stack";
			goto Bad;
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-4*BY2WD))

M port/devproc.c => port/devproc.c +39 -4
@@ 4,7 4,9 @@
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include 	"io.h"

/* BUG mips only TAKE IT OUT */
#include	"io.h"

#include	"devtab.h"



@@ 13,6 15,7 @@ enum{
	Qctl,
	Qmem,
	Qnote,
	Qnotepg,
	Qproc,
	Qstatus,
	Qtext,


@@ 22,6 25,7 @@ Dirtab procdir[]={
	"ctl",		Qctl,		0,			0600,
	"mem",		Qmem,		0,			0600,
	"note",		Qnote,		0,			0600,
	"notepg",	Qnotepg,	0,			0200,
	"proc",		Qproc,		sizeof(Proc),		0600,
	"status",	Qstatus,	NAMELEN+12+6*12,	0600,
	"text",		Qtext,		0,			0600,


@@ 109,6 113,7 @@ Chan *
procopen(Chan *c, int omode)
{
	Proc *p;
	Pgrp *pg;
	Orig *o;
	Chan *tc;



@@ 118,6 123,7 @@ procopen(Chan *c, int omode)
		goto done;
	}
	p = proctab(SLOT(c->qid));
	pg = p->pgrp;
	if((p->pid&PIDMASK) != PID(c->qid))
    Died:
		error(0, Eprocdied);


@@ 147,11 153,18 @@ procopen(Chan *c, int omode)
	case Qctl:
	case Qnote:
		break;

	case Qnotepg:
		if(omode != OWRITE)
			error(0, Eperm);
		c->pgrpid = (pg->pgrpid<<PIDSHIFT)|((pg->index+1)<<QSHIFT);
		break;

	case Qdir:
	case Qmem:
	case Qproc:
	case Qstatus:
		if(omode!=OREAD)
		if(omode != OREAD)
			error(0, Eperm);
		break;
	default:


@@ 264,7 277,7 @@ procread(Chan *c, void *va, long n)
		}

		/* u area */
		if(c->offset>=USERADDR && c->offset<=USERADDR+BY2PG){
		if(c->offset>=USERADDR && c->offset<USERADDR+BY2PG){
			if(c->offset+n > USERADDR+BY2PG)
				n = USERADDR+BY2PG - c->offset;
			pg = p->upage;


@@ 283,7 296,8 @@ procread(Chan *c, void *va, long n)
				n = KZERO+conf.npage0*BY2PG - c->offset;
			memcpy(a, (char*)c->offset, n);
			return n;
		} else if(c->offset>=UNCACHED && c->offset<UNCACHED+conf.npage0*BY2PG){
		}else if(c->offset>=UNCACHED && c->offset<UNCACHED+conf.npage0*BY2PG){
			/* BUT mips only TAKE IT OUT */
			if(c->offset+n > UNCACHED+conf.npage0*BY2PG)
				n = UNCACHED+conf.npage0*BY2PG - c->offset;
			memcpy(a, (char*)c->offset, n);


@@ 353,12 367,33 @@ long
procwrite(Chan *c, void *va, long n)
{
	Proc *p;
	Pgrp *pg;
	User *up;
	KMap *k;
	char buf[ERRLEN];

	if(c->qid & CHDIR)
		error(0, Eisdir);

	/*
	 * Special case: don't worry about process, just use remembered group
	 */
	if(QID(c->qid) == Qnotepg){
		pg = pgrptab(SLOT(c->pgrpid));
		lock(&pg->debug);
		if(waserror()){
			unlock(&pg->debug);
			nexterror();
		}
		if((pg->pgrpid&PIDMASK) != PID(c->pgrpid)){
			unlock(&pg->debug);
  	  		goto Died;
		}
		pgrpnote(pg, va, n, NUser);
		unlock(&pg->debug);
		return n;
	}

	p = proctab(SLOT(c->qid));
	lock(&p->debug);
	if(waserror()){

M port/devsrv.c => port/devsrv.c +72 -62
@@ 7,21 7,22 @@
#include	"devtab.h"
#include	"fcall.h"

void *calloc(unsigned int, unsigned int);
void *calloc(unsigned, unsigned);
void free(void *);

/* This structure holds the contents of a directory entry.  Entries are kept
 * in a linked list.
 */
struct entry {
typedef struct Entry Entry;
struct Entry {
	Lock;
	struct entry *next;	/* next entry */
	struct entry **back;	/* entry pointer */
	struct entry *parent;	/* parent directory */
	Entry *next;		/* next entry */
	Entry **back;		/* entry pointer */
	Entry *parent;		/* parent directory */
	Dir dir;		/* dir structure */
	union {
		Chan *chan;		/* if not a subdirectory */
		struct entry *entries;	/* directory entries */
	union{
		Chan *chan;	/* if not a subdirectory */
		Entry *entries;	/* directory entries */
	};
};



@@ 35,11 36,13 @@ srvreset(void)
{
}

struct entry *srv_alloc(int mode){
	struct entry *e = calloc(1, sizeof(*e));
Entry *
srvalloc(int mode){
	Entry *e;
	static Lock qidlock;
	static nextqid;

	e = calloc(1, sizeof(Entry));
	e->dir.atime = e->dir.mtime = seconds();
	lock(&qidlock);	/* for qid allocation */
	e->dir.qid = mode | nextqid++;


@@ 52,11 55,11 @@ srvattach(char *spec)
{
	Chan *c;
	static Lock rootlock;
	static struct entry *root;
	static Entry *root;

	lock(&rootlock);
	if (root == 0) {
		root = srv_alloc(CHDIR);
	if(root==0){
		root = srvalloc(CHDIR);
		root->dir.mode = CHDIR | 0777;
	}
	unlock(&rootlock);


@@ 77,23 80,23 @@ srvclone(Chan *c, Chan *nc)
int
srvwalk(Chan *c, char *name)
{
	struct entry *dir, *e;
	Entry *dir, *e;

	isdir(c);
	if (strcmp(name, ".") == 0)
	if(strcmp(name, ".") == 0)
		return 1;
	if ((dir = c->aux) == 0)
	if((dir=c->aux) == 0)
		panic("bad aux pointer in srvwalk");
	if (strcmp(name, "..") == 0)
	if(strcmp(name, "..") == 0)
		e = dir->parent;
	else {
	else{
		lock(dir);
		for (e = dir->entries; e != 0; e = e->next)
		for(e=dir->entries; e; e=e->next)
			if (strcmp(name, e->dir.name) == 0)
				break;
		unlock(dir);
	}
	if (e == 0) {
	if(e==0){
		u->error.code = Enonexist;
		u->error.type = 0;
		u->error.dev = 0;


@@ 107,32 110,33 @@ srvwalk(Chan *c, char *name)
void
srvstat(Chan *c, char *db)
{
	struct entry *e = c->aux;
	Entry *e;

	e = c->aux;
	convD2M(&e->dir, db);
}

Chan *
srvopen(Chan *c, int omode)
{
	struct entry *e;
	Entry *e;
	Chan *f;

	if (c->qid & CHDIR) {
		if (omode != OREAD)
	if(c->qid & CHDIR){
		if(omode != OREAD)
			error(0, Eisdir);
		c->mode = omode;
		c->flag |= COPEN;
		c->offset = 0;
		return c;
	}
	if ((e = c->aux) == 0)
		panic("bad aux pointer in srvopen");
	if ((f = e->chan) == 0)
	if((e=c->aux) == 0)
		error(0, Egreg);
	if((f=e->chan) == 0)
		error(0, Eshutdown);
	if (omode & OTRUNC)
	if(omode & OTRUNC)
		error(0, Eperm);
	if (omode != f->mode && f->mode != ORDWR)
	if(omode!=f->mode && f->mode!=ORDWR)
		error(0, Eperm);
	close(c);
	incref(f);


@@ 142,25 146,27 @@ srvopen(Chan *c, int omode)
void
srvcreate(Chan *c, char *name, int omode, ulong perm)
{
	struct entry *parent = c->aux, *e;
	Entry *parent, *e;

	parent = c->aux;
	isdir(c);
	lock(parent);
	if (waserror()) {
	if (waserror()){
		unlock(parent);
		nexterror();
	}
	for (e = parent->entries; e != 0; e = e->next)
		if (strcmp(name, e->dir.name) == 0)
	for(e=parent->entries; e; e=e->next)
		if(strcmp(name, e->dir.name) == 0)
			error(0, Einuse);
	e = srv_alloc(perm & CHDIR);
	e = srvalloc(perm & CHDIR);
	e->parent = parent;
	strcpy(e->dir.name, name);
	e->dir.mode = perm & parent->dir.mode;
	e->dir.gid = parent->dir.gid;
	if ((e->next = parent->entries) != 0)
	if(e->next = parent->entries)	/* assign = */
		e->next->back = &e->next;
	*(e->back = &parent->entries) = e;
	e->back = &parent->entries;
	*e->back = e;
	parent->dir.mtime = e->dir.mtime;
	unlock(parent);
	poperror();


@@ 173,25 179,25 @@ srvcreate(Chan *c, char *name, int omode, ulong perm)
void
srvremove(Chan *c)
{
	struct entry *e = c->aux;
	Entry *e;

	if (e->parent == 0)
	e = c->aux;
	if(e->parent == 0)
		error(0, Eperm);
	lock(e->parent);
	if (waserror()) {
	if(waserror()){
		unlock(e->parent);
		nexterror();
	}
	if (e->dir.mode & CHDIR) {
	if(e->dir.mode & CHDIR){
		if (e->entries != 0)
			error(0, Eperm);
	}
	else {
		if (e->chan == 0)
	}else{
		if(e->chan == 0)
			error(0, Eshutdown);
		close(e->chan);
	}
	if ((*e->back = e->next) != 0)
	if(*e->back = e->next)	/* assign = */
		e->next->back = e->back;
	unlock(e->parent);
	poperror();


@@ 213,11 219,13 @@ srvclose(Chan *c)
 * to a list of entries in this directory.  Count is the size to be
 * read.
 */
int srv_direntry(struct entry *e, char *a, long count){
int
srvdirentry(Entry *e, char *a, long count){
	Dir dir;
	int n = 0;
	int n;

	while (n != count && e != 0) {
	n = 0;
	while(n!=count && e!=0){
		n += convD2M(&e->dir, a + n);
		e = e->next;
	}


@@ 227,23 235,24 @@ int srv_direntry(struct entry *e, char *a, long count){
long
srvread(Chan *c, void *va, long n)
{
	struct entry *dir = c->aux, *e;
	int offset = c->offset;
	Entry *dir, *e;
	int offset;

	dir = c->aux;
	offset = c->offset;
	isdir(c);
	if (n <= 0)
	if(n <= 0)
		return 0;
	if ((offset % DIRLEN) != 0 || (n % DIRLEN) != 0)
		error(0, Egreg);
	if(offset%DIRLEN || n%DIRLEN)
		error(0, Ebaddirread);
	lock(dir);
	for (e = dir->entries; e != 0; e = e->next)
		if (offset <= 0) {
			n = srv_direntry(e, va, n);
	for(e=dir->entries; e; e=e->next)
		if(offset <= 0){
			n = srvdirentry(e, va, n);
			unlock(dir);
			c->offset += n;
			return n;
		}
		else
		}else
			offset -= DIRLEN;
	unlock(dir);
	return 0;


@@ 252,20 261,21 @@ srvread(Chan *c, void *va, long n)
long
srvwrite(Chan *c, void *va, long n)
{
	struct entry *e = c->aux;
	Entry *e;
	int i, fd;
	char buf[32];

	if (e->dir.mode & CHDIR)
	e = c->aux;
	if(e->dir.mode & CHDIR)
		panic("write to directory");
	lock(e);
	if (waserror()) {
	if(waserror()){
		unlock(e);
		nexterror();
	}
	if (e->chan != 0)
	if(e->chan)
		error(0, Egreg);
	if (n >= sizeof buf)
	if(n >= sizeof buf)
		error(0, Egreg);
	memcpy(buf, va, n);	/* so we can NUL-terminate */
	buf[n] = 0;

M port/fault.c => port/fault.c +4 -2
@@ 98,6 98,8 @@ fault(Ureg *ur, int user, int code)
				qunlock(o->chan);
				pg->o = 0;
				pg->ref--;
				if(user)
					pexit("Interrupt", 0);
				goto cant;
			}
			o->chan->offset = (addr-o->va) + o->minca;


@@ 218,7 220,7 @@ validaddr(ulong addr, ulong len, int write)
	if((long)len < 0){
    Err:
		pprint("invalid address in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
		postnote(u->p, 1, "bad address", NDebug);
		postnote(u->p, 1, "sys: bad address", NDebug);
		error(0, Ebadarg);
	}
    Again:


@@ 241,7 243,7 @@ void
evenaddr(ulong addr)
{
	if(addr & 3){
		postnote(u->p, 1, "odd address", NDebug);
		postnote(u->p, 1, "sys: odd address", NDebug);
		error(0, Ebadarg);
	}
}

M port/pgrp.c => port/pgrp.c +44 -1
@@ 7,6 7,7 @@

struct{
	Lock;
	Pgrp	*arena;
	Pgrp	*free;
	ulong	pgrpid;
}pgrpalloc;


@@ 24,10 25,12 @@ pgrpinit(void)
	Pgrp *p;
	Mount *m;

	pgrpalloc.free = ialloc(conf.npgrp*sizeof(Pgrp), 0);
	pgrpalloc.arena = ialloc(conf.npgrp*sizeof(Pgrp), 0);
	pgrpalloc.free = pgrpalloc.arena;

	p = pgrpalloc.free;
	for(i=0; i<conf.npgrp; i++,p++){
		p->index = i;
		p->next = p+1;
		p->mtab = ialloc(conf.nmtab*sizeof(Mtab), 0);
		p->etab = ialloc(conf.npgenv*sizeof(Envp*), 0);


@@ 43,6 46,43 @@ pgrpinit(void)
}

Pgrp*
pgrptab(int i)
{
	return &pgrpalloc.arena[i];
}

void
pgrpnote(Pgrp *pg, char *a, long n, int flag)
{
	int i;
	Proc *p;
	char buf[ERRLEN];

	if(n >= ERRLEN-1)
		error(0, Etoobig);
	if(n>=4 && strncmp(a, "sys:", 4)==0)
		error(0, Ebadarg);
	memcpy(buf, a, n);
	buf[n] = 0;
	p = proctab(0);
	for(i=0; i<conf.nproc; i++, p++){
		if(p->pgrp == pg){
			lock(&p->debug);
			if(p->pid==0 || p->pgrp!=pg){
				unlock(&p->debug);
				continue;
			}
			if(waserror()){
				unlock(&p->debug);
				continue;
			}
			postnote(p, 0, buf, flag);
			unlock(&p->debug);
		}
	}
}

Pgrp*
newpgrp(void)
{
	Pgrp *p;


@@ 76,6 116,8 @@ closepgrp(Pgrp *p)
	Envp *ep;

	if(decref(p) == 0){
		lock(&p->debug);
		p->pgrpid = -1;
		m = p->mtab;
		for(i=0; i<p->nmtab; i++,m++)
			if(m->c){


@@ 89,6 131,7 @@ closepgrp(Pgrp *p)
		lock(&pgrpalloc);
		p->next = pgrpalloc.free;
		pgrpalloc.free = p;
		unlock(&p->debug);
		unlock(&pgrpalloc);
	}
}

M power/dat.h => power/dat.h +3 -0
@@ 109,6 109,7 @@ struct Chan
	union{
		Stream	*stream;	/* for stream channels */
		void	*aux;
		ulong	pgrpid;		/* for #p/notepg */
	};
	Chan	*mchan;			/* channel to mounted server */
	ulong	mqid;			/* qid of root of mount point */


@@ 273,10 274,12 @@ struct Pgrp
{
	Ref;				/* also used as a lock when mounting */
	Pgrp	*next;
	int	index;			/* index in pgrp table */
	ulong	pgrpid;
	char	user[NAMELEN];
	int	nmtab;			/* highest active mount table entry, +1 */
	int	nenv;			/* highest active env table entry, +1 */
	Lock	debug;			/* single access via devproc.c */
	Mtab	*mtab;
	Envp	*etab;
};

M power/devhotrod.c => power/devhotrod.c +2 -0
@@ 136,6 136,7 @@ hotrodopen(Chan *c, int omode)
	Device *dp;
	Hotrod *hp;

#ifdef asdf
	/*
	 *  Remind hotrod where the print buffer is.  The address we store
	 *  is the address of the printbuf in VME A32 space.


@@ 143,6 144,7 @@ hotrodopen(Chan *c, int omode)
	hp = &hotrod[c->dev];
	dp = hp->addr;
	dp->mem[256*1024/sizeof(ulong)] = (((ulong)&hp->pbuf) - KZERO) | (SLAVE<<28);
#endif

	if(c->qid == CHDIR){
		if(omode != OREAD)

M power/fns.h => power/fns.h +2 -0
@@ 125,6 125,8 @@ void	panic(char*, ...);
void	pexit(char*, int);
void	pgrpcpy(Pgrp*, Pgrp*);
void	pgrpinit(void);
void	pgrpnote(Pgrp*, char*, long, int);
Pgrp	*pgrptab(int);
int	postnote(Proc*, int, char*, int);
int	pprint(char*, ...);
Block	*prepend(Block*, int);

M power/trap.c => power/trap.c +4 -4
@@ 155,9 155,9 @@ trap(Ureg *ur)
		if(user){
			spllo();
			if(ecode == FPEXC)
				sprint(buf, "fp: %s FCR31 %lux", fpexcname(x), x);
				sprint(buf, "sys: fp: %s FCR31 %lux", fpexcname(x), x);
			else
				sprint(buf, "trap: %s[%d]", excname[ecode], m->machno);
				sprint(buf, "sys: trap: %s[%d]", excname[ecode], m->machno);
			postnote(u->p, 1, buf, NDebug);
		}else{
			print("%s %s pc=%lux\n", user? "user": "kernel", excname[ecode], ur->pc);


@@ 463,14 463,14 @@ syscall(Ureg *aur)
	if(!waserror()){
		if(r1 >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", r1, ((Ureg*)UREGADDR)->pc);
			msg = "bad sys call";
			msg = "sys: bad sys call";
	    Bad:
			postnote(u->p, 1, msg, NDebug);
			error(0, Ebadarg);
		}
		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "odd stack";
			msg = "sys: odd stack";
			goto Bad;
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-4*BY2WD))