plan 9 kernel history: overview | file list | diff list

1999/0820/port/devcons.c (diff list | history)

port/devcons.c on 1990/0227
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
1997/0327    
void	(*consdebug)(void); 
1990/0227    
 
1997/0327    
Queue*	kbdq;			/* unprocessed console input */ 
Queue*	lineq;			/* processed console input */ 
Queue*	printq;			/* console output */ 
1990/0227    
 
1993/0601    
static struct 
{ 
	QLock; 
1990/0227    
 
1993/0601    
	int	raw;		/* true if we shouldn't process input */ 
	int	ctl;		/* number of opens to the control file */ 
	int	x;		/* index into line */ 
	char	line[1024];	/* current input line */ 
1990/0227    
 
1995/0815    
	Rune	c; 
1993/0601    
	int	count; 
	int	repeat; 
1995/0112    
	int	ctlpoff; 
1993/0601    
} kbd; 
 
1992/0321    
char	sysname[NAMELEN]; 
1999/0219    
vlong	fasthz; 
1991/1109    
 
1997/0327    
static ulong	randomread(void*, ulong); 
1996/1031    
static void	randominit(void); 
1998/0731    
static void	seedrand(void); 
1999/0711    
static int	readtime(ulong, char*, int); 
static int	readbintime(char*, int); 
static int	writetime(char*, int); 
static int	writebintime(char*, int); 
1995/0910    
 
1990/0227    
void 
1991/0607    
printinit(void) 
1990/0227    
{ 
1993/0601    
	lineq = qopen(2*1024, 0, 0, 0); 
1997/1105    
	if(lineq == nil) 
		panic("printinit"); 
1994/0902    
	qnoblock(lineq, 1); 
1990/0227    
} 
 
1997/0327    
int 
consactive(void) 
{ 
	if(printq) 
		return qlen(printq) > 0; 
	return 0; 
} 
 
void 
prflush(void) 
{ 
	while(consactive()) 
		; 
} 
 
1990/0227    
/* 
1991/0809    
 *   Print a string on the console.  Convert \n to \r\n for serial 
 *   line consoles.  Locking of the queues is left up to the screen 
 *   or uart code.  Multi-line messages to serial consoles may get 
 *   interspersed with other messages. 
1990/0227    
 */ 
1994/0208    
static void 
putstrn0(char *str, int n, int usewrite) 
1990/0227    
{ 
1994/1124    
	int m; 
1990/0227    
	char *t; 
1993/0806    
	char buf[PRINTSIZE+2]; 
1990/0227    
 
1991/0809    
	/* 
	 *  if there's an attached bit mapped display, 
	 *  put the message there.  screenputs is defined 
	 *  as a null macro for systems that have no such 
	 *  display. 
	 */ 
	screenputs(str, n); 
 
	/* 
	 *  if there's a serial line being used as a console, 
1993/0807    
	 *  put the message there. 
1991/0809    
	 */ 
1993/0601    
	if(printq == 0) 
1991/0809    
		return; 
1993/0806    
 
	while(n > 0) { 
1991/0809    
		t = memchr(str, '\n', n); 
1993/0806    
		if(t) { 
1991/0809    
			m = t - str; 
			memmove(buf, str, m); 
			buf[m] = '\r'; 
			buf[m+1] = '\n'; 
1994/0208    
			if(usewrite) 
1994/0902    
				qwrite(printq, buf, m+2); 
1994/1124    
			else 
				qiwrite(printq, buf, m+2); 
1991/0809    
			str = t + 1; 
			n -= m + 1; 
1994/0208    
		} else { 
			if(usewrite) 
1994/0902    
				qwrite(printq, str, n); 
1998/0512    
			else 
1994/1124    
				qiwrite(printq, str, n); 
1991/0809    
			break; 
		} 
1990/0227    
	} 
} 
 
1994/0208    
void 
putstrn(char *str, int n) 
{ 
	putstrn0(str, n, 0); 
} 
 
1990/0227    
int 
1995/0117    
snprint(char *s, int n, char *fmt, ...) 
{ 
1996/0214    
	va_list arg; 
 
	va_start(arg, fmt); 
	n = doprint(s, s+n, fmt, arg) - s; 
	va_end(arg); 
	return n; 
1995/0117    
} 
 
int 
1990/0227    
sprint(char *s, char *fmt, ...) 
{ 
1996/0214    
	int n; 
1997/0327    
	va_list arg; 
1996/0214    
 
	va_start(arg, fmt); 
	n = doprint(s, s+PRINTSIZE, fmt, arg) - s; 
	va_end(arg); 
	return n; 
1990/0227    
} 
 
int 
print(char *fmt, ...) 
{ 
	int n; 
1997/0327    
	va_list arg; 
	char buf[PRINTSIZE]; 
1990/0227    
 
1996/0214    
	va_start(arg, fmt); 
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; 
	va_end(arg); 
1990/0227    
	putstrn(buf, n); 
1993/0806    
 
1990/0227    
	return n; 
} 
 
1999/0820    
int 
iprint(char *fmt, ...) 
{ 
	int n, s; 
	va_list arg; 
	char buf[PRINTSIZE]; 
 
	s = splhi(); 
	va_start(arg, fmt); 
	n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; 
	va_end(arg); 
	serialputs(buf, n); 
	splx(s); 
 
	return n; 
} 
 
1990/0227    
void 
panic(char *fmt, ...) 
{ 
	int n; 
1997/0327    
	va_list arg; 
	char buf[PRINTSIZE]; 
1990/0227    
 
1991/1011    
	strcpy(buf, "panic: "); 
1996/0214    
	va_start(arg, fmt); 
	n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg) - buf; 
	va_end(arg); 
1990/0227    
	buf[n] = '\n'; 
	putstrn(buf, n+1); 
1994/0224    
	spllo(); 
1993/0829    
	prflush(); 
1990/0907    
	dumpstack(); 
1994/0219    
 
1992/0812    
	exit(1); 
1990/0227    
} 
1994/0305    
 
1990/0227    
int 
pprint(char *fmt, ...) 
{ 
1997/0327    
	int n; 
1990/0227    
	Chan *c; 
1996/0214    
	va_list arg; 
1997/0327    
	char buf[2*PRINTSIZE]; 
1990/0227    
 
1993/0501    
	if(up->fgrp == 0) 
1991/0720    
		return 0; 
 
1993/0501    
	c = up->fgrp->fd[2]; 
1993/0330    
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR)) 
1990/0321    
		return 0; 
1998/0825    
	n = sprint(buf, "%s %lud: ", up->text, up->pid); 
1996/0214    
	va_start(arg, fmt); 
	n = doprint(buf+n, buf+sizeof(buf), fmt, arg) - buf; 
	va_end(arg); 
1992/0825    
 
1993/0401    
	if(waserror()) 
		return 0; 
1997/0327    
	devtab[c->type]->write(c, buf, n, c->offset); 
1993/0401    
	poperror(); 
1992/0825    
 
	lock(c); 
1990/0227    
	c->offset += n; 
1992/0825    
	unlock(c); 
1993/0330    
 
1990/0227    
	return n; 
} 
 
void 
1991/1223    
echo(Rune r, char *buf, int n) 
1990/0227    
{ 
1993/1016    
	static int ctrlt, pid; 
	extern ulong etext; 
1998/0808    
	int x; 
1990/03091    
 
1990/0227    
	/* 
1991/0607    
	 * ^p hack 
1990/0227    
	 */ 
1996/0119    
	if(r==0x10 && cpuserver && !kbd.ctlpoff){ 
		lock(&active); 
		active.exiting = 1; 
		unlock(&active); 
	} 
1991/0608    
 
1991/0607    
	/* 
	 * ^t hack BUG 
	 */ 
1994/0313    
	if(ctrlt == 2){ 
1991/0607    
		ctrlt = 0; 
1991/1223    
		switch(r){ 
1991/0607    
		case 0x14: 
			break;	/* pass it on */ 
1994/0813    
		case 's': 
			dumpstack(); 
			break; 
1992/0619    
		case 'x': 
			xsummary(); 
1993/0819    
			ixsummary(); 
1999/0710    
			mallocsummary(); 
1999/0110    
			pagersummary(); 
1992/0619    
			break; 
1992/0411    
		case 'd': 
1997/0327    
			if(consdebug != nil) 
				consdebug(); 
1999/0820    
			return; 
		case 'D': 
			consdebug = rdb; 
1992/0411    
			return; 
1991/0607    
		case 'p': 
1998/0808    
			x = spllo(); 
1991/0608    
			procdump(); 
1998/0808    
			splx(x); 
1991/0607    
			return; 
1995/1030    
		case 'q': 
			scheddump(); 
			break; 
1995/0319    
		case 'k': 
			if(!cpuserver) 
				killbig(); 
			break; 
1991/0607    
		case 'r': 
1992/0812    
			exit(0); 
1991/0607    
			break; 
		} 
1994/0313    
	} 
	else if(r == 0x14){ 
		ctrlt++; 
		return; 
1991/0607    
	} 
	ctrlt = 0; 
1993/0601    
	if(kbd.raw) 
1991/0607    
		return; 
1993/0601    
 
	/* 
	 *  finally, the actual echoing 
	 */ 
1993/1005    
	if(r == '\n'){ 
		if(printq) 
1994/1124    
			qiwrite(printq, "\r", 1); 
1993/1005    
	} else if(r == 0x15){ 
		buf = "^U\n"; 
		n = 3; 
	} 
	screenputs(buf, n); 
	if(printq) 
1994/1124    
		qiwrite(printq, buf, n); 
1990/0227    
} 
 
/* 
1993/0601    
 *  Called by a uart interrupt for console input. 
 * 
 *  turn '\r' into '\n' before putting it into the queue. 
1991/0727    
 */ 
int 
1993/0601    
kbdcr2nl(Queue *q, int ch) 
1991/0727    
{ 
	if(ch == '\r') 
		ch = '\n'; 
	return kbdputc(q, ch); 
} 
 
/* 
1991/1223    
 *  Put character, possibly a rune, into read queue at interrupt time. 
1993/0601    
 *  Called at interrupt time to process a character. 
1990/0227    
 */ 
1991/0607    
int 
1995/0804    
kbdputc(Queue*, int ch) 
1990/0227    
{ 
1993/0601    
	int n; 
1991/1223    
	char buf[3]; 
	Rune r; 
 
	r = ch; 
	n = runetochar(buf, &r); 
	if(n == 0) 
		return 0; 
	echo(r, buf, n); 
1995/0815    
	kbd.c = r; 
1993/0601    
	qproduce(kbdq, buf, n); 
1991/0607    
	return 0; 
1990/0227    
} 
 
void 
1991/0607    
kbdrepeat(int rep) 
1990/0227    
{ 
1993/0601    
	kbd.repeat = rep; 
	kbd.count = 0; 
1991/0607    
} 
1990/0227    
 
1991/0607    
void 
kbdclock(void) 
{ 
1993/0601    
	if(kbd.repeat == 0) 
1991/0607    
		return; 
1993/0601    
	if(kbd.repeat==1 && ++kbd.count>HZ){ 
		kbd.repeat = 2; 
		kbd.count = 0; 
1991/0607    
		return; 
1990/0227    
	} 
1993/0601    
	if(++kbd.count&1) 
		kbdputc(kbdq, kbd.c); 
1990/0227    
} 
 
enum{ 
1992/0506    
	Qdir, 
1993/0330    
	Qauth, 
	Qauthcheck, 
1993/0731    
	Qauthent, 
1999/0711    
	Qbintime, 
1990/0227    
	Qcons, 
1991/1224    
	Qconsctl, 
1990/0227    
	Qcputime, 
1997/0410    
	Qdrivers, 
1992/0428    
	Qkey, 
1993/0330    
	Qhostdomain, 
	Qhostowner, 
1990/0227    
	Qnull, 
	Qpgrpid, 
	Qpid, 
	Qppid, 
1995/0910    
	Qrandom, 
1996/03071    
	Qreboot, 
1991/0705    
	Qswap, 
1992/0321    
	Qsysname, 
1992/0428    
	Qsysstat, 
	Qtime, 
	Quser, 
1999/0710    
	Qzero, 
1990/0227    
}; 
 
1999/0728    
enum 
{ 
	VLNUMSIZE=	22, 
}; 
 
1997/0410    
static Dirtab consdir[]={ 
1993/0330    
	"authenticate",	{Qauth},	0,		0666, 
	"authcheck",	{Qauthcheck},	0,		0666, 
1993/0731    
	"authenticator", {Qauthent},	0,		0666, 
1999/0711    
	"bintime",	{Qbintime},	24,		0664, 
1991/1211    
	"cons",		{Qcons},	0,		0660, 
1991/1224    
	"consctl",	{Qconsctl},	0,		0220, 
1991/1127    
	"cputime",	{Qcputime},	6*NUMSIZE,	0444, 
1997/0410    
	"drivers",	{Qdrivers},	0,		0644, 
1993/0402    
	"hostdomain",	{Qhostdomain},	DOMLEN,		0664, 
	"hostowner",	{Qhostowner},	NAMELEN,	0664, 
1992/0428    
	"key",		{Qkey},		DESKEYLEN,	0622, 
1991/1112    
	"null",		{Qnull},	0,		0666, 
1991/1127    
	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444, 
	"pid",		{Qpid},		NUMSIZE,	0444, 
	"ppid",		{Qppid},	NUMSIZE,	0444, 
1995/0910    
	"random",	{Qrandom},	0,		0664, 
1996/03071    
	"reboot",	{Qreboot},	0,		0664, 
1991/1211    
	"swap",		{Qswap},	0,		0664, 
1992/0428    
	"sysname",	{Qsysname},	0,		0664, 
	"sysstat",	{Qsysstat},	0,		0666, 
1999/0728    
	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664, 
1998/0808    
	"user",		{Quser},	NAMELEN,	0666, 
1999/0714    
	"zero",		{Qzero},	0,		0444, 
1990/0227    
}; 
 
int 
readnum(ulong off, char *buf, ulong n, ulong val, int size) 
{ 
	char tmp[64]; 
 
1998/0825    
	snprint(tmp, sizeof(tmp), "%*.0lud", size-1, val); 
1990/0227    
	tmp[size-1] = ' '; 
1990/0312    
	if(off >= size) 
		return 0; 
1990/0227    
	if(off+n > size) 
		n = size-off; 
1991/0318    
	memmove(buf, tmp+off, n); 
1990/0227    
	return n; 
} 
 
int 
readstr(ulong off, char *buf, ulong n, char *str) 
{ 
	int size; 
 
	size = strlen(str); 
1990/0312    
	if(off >= size) 
		return 0; 
1990/0227    
	if(off+n > size) 
		n = size-off; 
1991/0318    
	memmove(buf, str+off, n); 
1990/0227    
	return n; 
} 
 
1997/0327    
static void 
1990/0227    
consinit(void) 
{ 
1999/0219    
	todinit(); 
1995/0913    
	randominit(); 
1990/0227    
} 
 
1997/0327    
static Chan* 
1990/0227    
consattach(char *spec) 
{ 
	return devattach('c', spec); 
} 
 
1997/0327    
static int 
1990/0227    
conswalk(Chan *c, char *name) 
{ 
1997/0327    
	return devwalk(c, name, consdir, nelem(consdir), devgen); 
1990/0227    
} 
 
1997/0327    
static void 
1990/0227    
consstat(Chan *c, char *dp) 
{ 
1997/0327    
	devstat(c, dp, consdir, nelem(consdir), devgen); 
1990/0227    
} 
 
1997/0327    
static Chan* 
1990/0227    
consopen(Chan *c, int omode) 
{ 
1993/0330    
	c->aux = 0; 
1991/0607    
	switch(c->qid.path){ 
1991/1224    
	case Qconsctl: 
1993/0330    
		if(!iseve()) 
1991/0620    
			error(Eperm); 
1993/0601    
		qlock(&kbd); 
		kbd.ctl++; 
		qunlock(&kbd); 
1991/0607    
		break; 
1990/0227    
	} 
1997/0327    
	return devopen(c, omode, consdir, nelem(consdir), devgen); 
1990/0227    
} 
 
1997/0327    
static void 
1990/0227    
consclose(Chan *c) 
{ 
1991/1224    
	/* last close of control file turns off raw */ 
1993/0330    
	switch(c->qid.path){ 
	case Qconsctl: 
		if(c->flag&COPEN){ 
1993/0601    
			qlock(&kbd); 
			if(--kbd.ctl == 0) 
				kbd.raw = 0; 
			qunlock(&kbd); 
1993/0330    
		} 
1993/1031    
		break; 
1993/0330    
	case Qauth: 
	case Qauthcheck: 
1993/0731    
	case Qauthent: 
1993/0330    
		authclose(c); 
1991/1224    
	} 
1990/0227    
} 
 
1997/0327    
static long 
1998/0319    
consread(Chan *c, void *buf, long n, vlong off) 
1990/0227    
{ 
	ulong l; 
1991/0425    
	Mach *mp; 
1993/0725    
	char *b, *bp; 
	char tmp[128];		/* must be >= 6*NUMSIZE */ 
	char *cbuf = buf; 
	int ch, i, k, id, eol; 
1999/0711    
	vlong offset = off; 
1990/0227    
 
	if(n <= 0) 
		return n; 
1990/11211    
	switch(c->qid.path & ~CHDIR){ 
1990/0227    
	case Qdir: 
1997/0327    
		return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 
1990/0227    
 
	case Qcons: 
1993/0601    
		qlock(&kbd); 
1997/0327    
		if(waserror()) { 
1993/0601    
			qunlock(&kbd); 
1990/0617    
			nexterror(); 
		} 
1997/0820    
		if(kbd.raw) { 
			if(qcanread(lineq)) 
				n = qread(lineq, buf, n); 
1997/0821    
			else { 
				/* read as much as possible */ 
				do { 
					i = qread(kbdq, cbuf, n); 
					cbuf += i; 
					n -= i; 
				} while (n>0 && qcanread(kbdq)); 
				n = cbuf - (char*)buf; 
			} 
1997/0820    
		} else { 
			while(!qcanread(lineq)) { 
				qread(kbdq, &kbd.line[kbd.x], 1); 
				ch = kbd.line[kbd.x]; 
				if(kbd.raw){ 
					qiwrite(lineq, kbd.line, kbd.x+1); 
					kbd.x = 0; 
					continue; 
				} 
				eol = 0; 
				switch(ch){ 
				case '\b': 
					if(kbd.x) 
						kbd.x--; 
					break; 
				case 0x15: 
					kbd.x = 0; 
					break; 
				case '\n': 
				case 0x04: 
					eol = 1; 
				default: 
					kbd.line[kbd.x++] = ch; 
					break; 
				} 
				if(kbd.x == sizeof(kbd.line) || eol){ 
					if(ch == 0x04) 
						kbd.x--; 
					qwrite(lineq, kbd.line, kbd.x); 
					kbd.x = 0; 
				} 
1993/0601    
			} 
1997/0820    
			n = qread(lineq, buf, n); 
1990/0227    
		} 
1993/0601    
		qunlock(&kbd); 
1993/0725    
		poperror(); 
1993/0601    
		return n; 
1990/0227    
 
	case Qcputime: 
1991/0411    
		k = offset; 
1993/0408    
		if(k >= 6*NUMSIZE) 
1990/0312    
			return 0; 
1993/0408    
		if(k+n > 6*NUMSIZE) 
			n = 6*NUMSIZE - k; 
1990/0227    
		/* easiest to format in a separate buffer and copy out */ 
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){ 
1993/0501    
			l = up->time[i]; 
1990/0227    
			if(i == TReal) 
				l = MACHP(0)->ticks - l; 
1990/0614    
			l = TK2MS(l); 
1990/0227    
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 
		} 
1991/0318    
		memmove(buf, tmp+k, n); 
1990/0227    
		return n; 
 
	case Qpgrpid: 
1998/0617    
		return readnum((ulong)offset, buf, n, up->pgrp->pgrpid, NUMSIZE); 
1990/0227    
 
	case Qpid: 
1998/0617    
		return readnum((ulong)offset, buf, n, up->pid, NUMSIZE); 
1990/0227    
 
	case Qppid: 
1998/0617    
		return readnum((ulong)offset, buf, n, up->parentpid, NUMSIZE); 
1990/0227    
 
1999/0711    
	case Qtime: 
		return readtime((ulong)offset, buf, n); 
1998/0710    
 
1999/0711    
	case Qbintime: 
		return readbintime(buf, n); 
1998/0710    
 
1993/0330    
	case Qkey: 
		return keyread(buf, n, offset); 
1991/1127    
 
1993/0330    
	case Qauth: 
		return authread(c, cbuf, n); 
1992/0323    
 
1998/0422    
	case Qauthcheck: 
		return authcheckread(c, cbuf, n); 
 
1993/0731    
	case Qauthent: 
		return authentread(c, cbuf, n); 
 
1993/0330    
	case Qhostowner: 
1998/0617    
		return readstr((ulong)offset, buf, n, eve); 
1991/1127    
 
1993/0330    
	case Qhostdomain: 
1998/0617    
		return readstr((ulong)offset, buf, n, hostdomain); 
1993/0330    
 
1990/0227    
	case Quser: 
1998/0617    
		return readstr((ulong)offset, buf, n, up->user); 
1990/0227    
 
1991/0607    
	case Qnull: 
		return 0; 
 
1991/0425    
	case Qsysstat: 
1992/0814    
		b = smalloc(conf.nmach*(NUMSIZE*8+1) + 1);	/* +1 for NUL */ 
		bp = b; 
1991/0425    
		for(id = 0; id < 32; id++) { 
			if(active.machs & (1<<id)) { 
				mp = MACHP(id); 
1992/0814    
				readnum(0, bp, NUMSIZE, id, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->cs, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->intr, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->syscall, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->pfault, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->tlbfault, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->tlbpurge, NUMSIZE); 
				bp += NUMSIZE; 
				readnum(0, bp, NUMSIZE, mp->load, NUMSIZE); 
				bp += NUMSIZE; 
				*bp++ = '\n'; 
1991/0425    
			} 
		} 
1998/0617    
		n = readstr((ulong)offset, buf, n, b); 
1992/0814    
		free(b); 
		return n; 
1990/0227    
 
1991/0705    
	case Qswap: 
1998/0825    
		sprint(tmp, "%lud/%lud memory %lud/%lud swap\n", 
1993/1120    
			palloc.user-palloc.freecount, 
1993/0910    
			palloc.user, conf.nswap-swapalloc.free, conf.nswap); 
1991/0705    
 
1998/0617    
		return readstr((ulong)offset, buf, n, tmp); 
1992/0321    
 
	case Qsysname: 
1998/0617    
		return readstr((ulong)offset, buf, n, sysname); 
1992/0321    
 
1995/0910    
	case Qrandom: 
		return randomread(buf, n); 
1997/0410    
 
	case Qdrivers: 
1997/0417    
		b = malloc(READSTR); 
1997/0410    
		if(b == nil) 
			error(Enomem); 
		n = 0; 
		for(i = 0; devtab[i] != nil; i++) 
1997/0417    
			n += snprint(b+n, READSTR-n, "#%C %s\n", devtab[i]->dc,  devtab[i]->name); 
1998/0617    
		n = readstr((ulong)offset, buf, n, b); 
1997/0410    
		free(b); 
		return n; 
1995/0910    
 
1999/0710    
	case Qzero: 
		memset(buf, 0, n); 
		return n; 
 
1990/0227    
	default: 
1998/0811    
		print("consread %lux\n", c->qid.path); 
1991/1127    
		error(Egreg); 
1990/0227    
	} 
1992/0520    
	return -1;		/* never reached */ 
1990/0227    
} 
 
1997/0327    
static long 
1998/0319    
conswrite(Chan *c, void *va, long n, vlong off) 
1990/0227    
{ 
	char buf[256]; 
1991/1116    
	long l, bp; 
1993/0330    
	char *a = va; 
1991/0425    
	Mach *mp; 
1993/0601    
	int id, fd; 
1991/0705    
	Chan *swc; 
1998/0319    
	ulong offset = off; 
1990/0227    
 
1990/11211    
	switch(c->qid.path){ 
1990/0227    
	case Qcons: 
		/* 
1991/1206    
		 * Can't page fault in putstrn, so copy the data locally. 
1990/0227    
		 */ 
		l = n; 
		while(l > 0){ 
1991/1116    
			bp = l; 
			if(bp > sizeof buf) 
				bp = sizeof buf; 
			memmove(buf, a, bp); 
1994/0208    
			putstrn0(a, bp, 1); 
1991/1116    
			a += bp; 
			l -= bp; 
1991/1224    
		} 
		break; 
 
	case Qconsctl: 
		if(n >= sizeof(buf)) 
			n = sizeof(buf)-1; 
		strncpy(buf, a, n); 
		buf[n] = 0; 
		for(a = buf; a;){ 
			if(strncmp(a, "rawon", 5) == 0){ 
1993/0601    
				qlock(&kbd); 
				if(kbd.x){ 
1994/0902    
					qwrite(kbdq, kbd.line, kbd.x); 
1993/0601    
					kbd.x = 0; 
1991/1224    
				} 
1993/0601    
				kbd.raw = 1; 
				qunlock(&kbd); 
1991/1224    
			} else if(strncmp(a, "rawoff", 6) == 0){ 
1993/0601    
				kbd.raw = 0; 
1993/0725    
				kbd.x = 0; 
1995/0112    
			} else if(strncmp(a, "ctlpon", 6) == 0){ 
				kbd.ctlpoff = 0; 
			} else if(strncmp(a, "ctlpoff", 7) == 0){ 
				kbd.ctlpoff = 1; 
1991/1224    
			} 
			if(a = strchr(a, ' ')) 
				a++; 
1990/0227    
		} 
		break; 
 
	case Qtime: 
1999/0711    
		if(!iseve()) 
			error(Eperm); 
		return writetime(a, n); 
1999/0218    
 
1999/0711    
	case Qbintime: 
		if(!iseve()) 
			error(Eperm); 
		return writebintime(a, n); 
1999/0218    
 
1991/1127    
	case Qkey: 
1993/0330    
		return keywrite(a, n); 
1991/1127    
 
1993/0330    
	case Qhostowner: 
		return hostownerwrite(a, n); 
 
	case Qhostdomain: 
		return hostdomainwrite(a, n); 
 
1990/0227    
	case Quser: 
1993/0330    
		return userwrite(a, n); 
1990/0227    
 
1993/0330    
	case Qauth: 
		return authwrite(c, a, n); 
 
	case Qauthcheck: 
		return authcheck(c, a, n); 
1993/0731    
 
	case Qauthent: 
		return authentwrite(c, a, n); 
1993/0428    
 
1990/0227    
	case Qnull: 
		break; 
1990/11161    
 
1996/03071    
	case Qreboot: 
		if(!iseve()) 
			error(Eperm); 
1997/0831    
		if(strncmp(a, "reboot", 6) == 0){ 
			print("conswrite: reboot\n"); 
1996/03071    
			exit(0); 
1997/0831    
		} 
1999/0720    
		if(strncmp(a, "panic", 5) == 0) 
			panic("/dev/reboot"); 
1991/0607    
		break; 
 
1991/0425    
	case Qsysstat: 
		for(id = 0; id < 32; id++) { 
			if(active.machs & (1<<id)) { 
				mp = MACHP(id); 
				mp->cs = 0; 
				mp->intr = 0; 
				mp->syscall = 0; 
				mp->pfault = 0; 
				mp->tlbfault = 0; 
				mp->tlbpurge = 0; 
			} 
		} 
		break; 
1991/0705    
 
	case Qswap: 
		if(n >= sizeof buf) 
			error(Egreg); 
		memmove(buf, va, n);	/* so we can NUL-terminate */ 
		buf[n] = 0; 
1992/0825    
		/* start a pager if not already started */ 
1992/0310    
		if(strncmp(buf, "start", 5) == 0){ 
1992/0825    
			kickpager(); 
1992/0310    
			break; 
		} 
1993/0501    
		if(cpuserver && !iseve()) 
1992/0310    
			error(Eperm); 
		if(buf[0]<'0' || '9'<buf[0]) 
1992/0228    
			error(Ebadarg); 
1991/0705    
		fd = strtoul(buf, 0, 0); 
1998/0403    
		swc = fdtochan(fd, -1, 1, 1); 
1991/0705    
		setswapchan(swc); 
1992/0321    
		break; 
 
	case Qsysname: 
		if(offset != 0) 
			error(Ebadarg); 
		if(n <= 0 || n >= NAMELEN) 
			error(Ebadarg); 
		strncpy(sysname, a, n); 
		sysname[n] = 0; 
		if(sysname[n-1] == '\n') 
			sysname[n-1] = 0; 
1992/0310    
		break; 
1991/0607    
 
1990/0227    
	default: 
1998/0825    
		print("conswrite: %lud\n", c->qid.path); 
1990/11211    
		error(Egreg); 
1990/0227    
	} 
	return n; 
1995/0108    
} 
 
1990/0227    
void 
1991/1102    
setterm(char *f) 
{ 
	char buf[2*NAMELEN]; 
 
	sprint(buf, f, conffile); 
	ksetenv("terminal", buf); 
1995/0910    
} 
 
1997/0327    
Dev consdevtab = { 
1997/0408    
	'c', 
	"cons", 
 
1997/0327    
	devreset, 
	consinit, 
	consattach, 
	devclone, 
	conswalk, 
	consstat, 
	consopen, 
	devcreate, 
	consclose, 
	consread, 
	devbread, 
	conswrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 
 
1998/0829    
struct Rb 
1995/0910    
{ 
	QLock; 
1995/0913    
	Rendez	producer; 
	Rendez	consumer; 
1997/0327    
	ulong	randomcount; 
1998/0702    
	uchar	buf[1024]; 
1995/0910    
	uchar	*ep; 
	uchar	*rp; 
	uchar	*wp; 
	uchar	next; 
	uchar	wakeme; 
1996/1029    
	ushort	bits; 
	ulong	randn; 
1995/0910    
} rb; 
 
1996/1031    
static void 
1998/0731    
seedrand(void) 
1996/1031    
{ 
1997/0327    
	randomread((void*)&rb.randn, sizeof(rb.randn)); 
1996/1031    
} 
 
1996/1029    
int 
nrand(int n) 
{ 
1998/0731    
	if(rb.randn == 0) 
		seedrand(); 
1996/1029    
	rb.randn = rb.randn*1103515245 + 12345 + MACHP(0)->ticks; 
	return (rb.randn>>16) % n; 
} 
1995/0910    
 
1998/0731    
int 
rand(void) 
{ 
	nrand(1); 
	return rb.randn; 
} 
 
 
1995/0913    
static int 
rbnotfull(void*) 
{ 
	int i; 
 
	i = rb.rp - rb.wp; 
	return i != 1 && i != (1 - sizeof(rb.buf)); 
} 
 
1997/0327    
static int 
rbnotempty(void*) 
{ 
	return rb.wp != rb.rp; 
} 
 
1995/0910    
void 
1995/0913    
genrandom(void*) 
1995/0910    
{ 
1995/0913    
	up->basepri = PriNormal; 
	up->priority = up->basepri; 
 
	for(;;){ 
1995/1023    
		for(;;) 
1999/0713    
			if(++rb.randomcount > 100000) 
1995/1023    
				break; 
1998/0829    
		if(anyhigher()) 
			sched(); 
1995/0913    
		if(!rbnotfull(0)) 
			sleep(&rb.producer, rbnotfull, 0); 
	} 
} 
 
1995/0910    
/* 
 *  produce random bits in a circular buffer 
 */ 
1997/0413    
static void 
1995/0910    
randomclock(void) 
{ 
1995/1023    
	if(rb.randomcount == 0 || !rbnotfull(0)) 
1995/0910    
		return; 
 
1995/1023    
	rb.bits = (rb.bits<<2) ^ rb.randomcount; 
	rb.randomcount = 0; 
1995/0913    
 
1995/1023    
	rb.next++; 
	if(rb.next != 8/2) 
1995/0910    
		return; 
	rb.next = 0; 
 
1995/1023    
	*rb.wp ^= rb.bits; 
	if(rb.wp+1 == rb.ep) 
		rb.wp = rb.buf; 
	else 
		rb.wp = rb.wp+1; 
 
1995/0910    
	if(rb.wakeme) 
1995/0913    
		wakeup(&rb.consumer); 
1997/0413    
} 
 
static void 
randominit(void) 
{ 
	addclock0link(randomclock); 
	rb.ep = rb.buf + sizeof(rb.buf); 
	rb.rp = rb.wp = rb.buf; 
	kproc("genrandom", genrandom, 0); 
1995/0910    
} 
 
/* 
 *  consume random bytes from a circular buffer 
 */ 
static ulong 
1997/0327    
randomread(void *xp, ulong n) 
1995/0910    
{ 
1997/0327    
	uchar *e, *p; 
1997/0616    
	ulong x; 
1997/0327    
 
	p = xp; 
1995/0910    
 
	if(waserror()){ 
		qunlock(&rb); 
		nexterror(); 
	} 
 
	qlock(&rb); 
1995/1023    
	for(e = p + n; p < e; ){ 
		if(rb.wp == rb.rp){ 
1995/0910    
			rb.wakeme = 1; 
1995/1023    
			wakeup(&rb.producer); 
1995/0913    
			sleep(&rb.consumer, rbnotempty, 0); 
1995/0910    
			rb.wakeme = 0; 
			continue; 
		} 
1997/0616    
 
		/* 
		 *  beating clocks will be precictable if 
		 *  they are synchronized.  Use a cheap pseudo 
		 *  random number generator to obscure any cycles. 
		 */ 
		x = rb.randn*1103515245 ^ *rb.rp; 
		*p++ = rb.randn = x; 
 
1995/1023    
		if(rb.rp+1 == rb.ep) 
			rb.rp = rb.buf; 
		else 
			rb.rp = rb.rp+1; 
1995/0910    
	} 
	qunlock(&rb); 
	poperror(); 
1995/0913    
 
	wakeup(&rb.producer); 
1995/0910    
 
1999/0711    
	return n; 
} 
 
static uvlong uvorder = 0x0001020304050607ULL; 
 
static uchar* 
le2vlong(vlong *to, uchar *f) 
{ 
	uchar *t, *o; 
	int i; 
 
	t = (uchar*)to; 
	o = (uchar*)&uvorder; 
	for(i = 0; i < sizeof(vlong); i++) 
		t[o[i]] = f[i]; 
	return f+sizeof(vlong); 
} 
 
static uchar* 
vlong2le(uchar *t, vlong from) 
{ 
	uchar *f, *o; 
	int i; 
 
	f = (uchar*)&from; 
	o = (uchar*)&uvorder; 
	for(i = 0; i < sizeof(vlong); i++) 
		t[i] = f[o[i]]; 
	return t+sizeof(vlong); 
} 
 
static long order = 0x00010203; 
 
static uchar* 
le2long(long *to, uchar *f) 
{ 
	uchar *t, *o; 
	int i; 
 
	t = (uchar*)to; 
	o = (uchar*)ℴ 
	for(i = 0; i < sizeof(long); i++) 
		t[o[i]] = f[i]; 
	return f+sizeof(long); 
} 
 
static uchar* 
long2le(uchar *t, long from) 
{ 
	uchar *f, *o; 
	int i; 
 
	f = (uchar*)&from; 
	o = (uchar*)ℴ 
	for(i = 0; i < sizeof(long); i++) 
		t[i] = f[o[i]]; 
	return t+sizeof(long); 
} 
 
char *Ebadtimectl = "bad time control"; 
 
/* 
 *  like the old #c/time but with added info.  Return 
 * 
 *	secs	nanosecs	fastticks	fasthz 
 */ 
static int 
readtime(ulong off, char *buf, int n) 
{ 
	vlong	nsec, ticks; 
	long sec; 
	char str[7*NUMSIZE+4];	// extra 4 bytes are null plus doprint 
				// reserving space for a frigging UTF 
				// char 
 
	nsec = todget(&ticks); 
	if(fasthz == 0LL) 
		fastticks((uvlong*)&fasthz); 
	sec = nsec/1000000000ULL; 
	snprint(str, sizeof(str), "%*.0lud %*.0llud %*.0llud %*.0llud ", 
		NUMSIZE-1, sec, 
1999/0728    
		VLNUMSIZE-1, nsec, 
		VLNUMSIZE-1, ticks, 
		VLNUMSIZE-1, fasthz); 
1999/0711    
	return readstr(off, buf, n, str); 
} 
 
/* 
 *  set the time in seconds 
 */ 
static int 
writetime(char *buf, int n) 
{ 
	char b[13]; 
	long i; 
	vlong now; 
 
	if(n >= sizeof(b)) 
		error(Ebadtimectl); 
	strncpy(b, buf, n); 
	b[n] = 0; 
	i = strtol(b, 0, 0); 
	if(i <= 0) 
		error(Ebadtimectl); 
	now = i*1000000000LL; 
	todset(now, 0, 0); 
	return n; 
} 
 
/* 
 *  read binary time info.  all numbers are little endian. 
 *  ticks and nsec are syncronized. 
 */ 
static int 
readbintime(char *buf, int n) 
{ 
	int i; 
	vlong nsec, ticks; 
	uchar *b = (uchar*)buf; 
 
	i = 0; 
	if(fasthz == 0LL) 
		fastticks((uvlong*)&fasthz); 
	nsec = todget(&ticks); 
	if(n >= 3*sizeof(uvlong)){ 
		vlong2le(b+2*sizeof(uvlong), fasthz); 
		i += sizeof(uvlong); 
	} 
	if(n >= 2*sizeof(uvlong)){ 
		vlong2le(b+sizeof(uvlong), ticks); 
		i += sizeof(uvlong); 
	} 
	if(n >= 8){ 
		vlong2le(b, nsec); 
		i += sizeof(vlong); 
	} 
	return i; 
} 
 
/* 
 *  set any of the following 
 *	- time in nsec 
 *	- nsec trim applied over some seconds 
 *	- clock frequency 
 */ 
static int 
writebintime(char *buf, int n) 
{ 
	uchar *p; 
	vlong delta; 
	long period; 
 
	n--; 
	p = (uchar*)buf + 1; 
	switch(*buf){ 
	case 'n': 
		if(n < sizeof(vlong)) 
			error(Ebadtimectl); 
		le2vlong(&delta, p); 
		todset(delta, 0, 0); 
		break; 
	case 'd': 
		if(n < sizeof(vlong)+sizeof(long)) 
			error(Ebadtimectl); 
		p = le2vlong(&delta, p); 
		le2long(&period, p); 
		todset(-1, delta, period); 
		break; 
	case 'f': 
		if(n < sizeof(uvlong)) 
			error(Ebadtimectl); 
		le2vlong(&fasthz, p); 
		todsetfreq(fasthz); 
		break; 
	} 
1995/0910    
	return n; 
1991/1102    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)