1069 lines · 18.4 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"pool.h" #include	<authsrv.h> void	(*consdebug)(void) = nil;void	(*screenputs)(char*, int) = nil; Queue*	serialoq;		/* serial console output */Queue*	kprintoq;		/* console output, for /dev/kprint */ulong	kprintinuse;		/* test and set whether /dev/kprint is open */int	iprintscreenputs = 1; int	panicking; char	*sysname;vlong	fasthz; static void	seedrand(void);static int	readtime(ulong, char*, int);static int	readbintime(char*, int);static int	writetime(char*, int);static int	writebintime(char*, int); enum{	CMhalt,	CMreboot,	CMpanic,	CMrdb,}; Cmdtab rebootmsg[] ={	CMhalt,		"halt",		1,	CMreboot,	"reboot",	0,	CMpanic,	"panic",	0,	CMrdb,		"rdb",		0,}; voidprintinit(void){} intconsactive(void){	if(serialoq)		return qlen(serialoq) > 0;	return 0;} voidprflush(void){	ulong now; 	now = m->ticks;	while(consactive())		if(m->ticks - now >= HZ)			break;} /* * Log console output so it can be retrieved via /dev/kmesg. * This is good for catching boot-time messages after the fact. */struct {	Lock lk;	char buf[16384];	uint n;} kmesg; static voidkmesgputs(char *str, int n){	uint nn, d; 	ilock(&kmesg.lk);	/* take the tail of huge writes */	if(n > sizeof kmesg.buf){		d = n - sizeof kmesg.buf;		str += d;		n -= d;	} 	/* slide the buffer down to make room */	nn = kmesg.n;	if(nn + n >= sizeof kmesg.buf){		d = nn + n - sizeof kmesg.buf;		if(d)			memmove(kmesg.buf, kmesg.buf+d, sizeof kmesg.buf-d);		nn -= d;	} 	/* copy the data in */	memmove(kmesg.buf+nn, str, n);	nn += n;	kmesg.n = nn;	iunlock(&kmesg.lk);} /* *   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. */static voidputstrn0(char *str, int n, int usewrite){	int m;	char *t; 	if(!islo())		usewrite = 0; 	/*	 *  how many different output devices do we need?	 */	kmesgputs(str, n); 	/*	 *  if someone is reading /dev/kprint,	 *  put the message there.	 *  if not and there's an attached bit mapped display,	 *  put the message there.	 *	 *  if there's a serial line being used as a console,	 *  put the message there.	 */	if(kprintoq != nil && !qisclosed(kprintoq)){		if(usewrite)			qwrite(kprintoq, str, n);		else			qiwrite(kprintoq, str, n);	}else if(screenputs != nil)		screenputs(str, n); 	if(serialoq == nil){		uartputs(str, n);		return;	} 	while(n > 0) {		t = memchr(str, '\n', n);		if(t != nil) {			m = t-str;			if(usewrite){				qwrite(serialoq, str, m);				qwrite(serialoq, "\r\n", 2);			} else {				qiwrite(serialoq, str, m);				qiwrite(serialoq, "\r\n", 2);			}			n -= m+1;			str = t+1;		} else {			if(usewrite)				qwrite(serialoq, str, n);			else				qiwrite(serialoq, str, n);			break;		}	}} voidputstrn(char *str, int n){	putstrn0(str, n, 0);} intprint(char *fmt, ...){	int n;	va_list arg;	char buf[PRINTSIZE]; 	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg);	putstrn(buf, n); 	return n;} /* * Want to interlock iprints to avoid interlaced output on  * multiprocessor, but don't want to deadlock if one processor * dies during print and another has something important to say. * Make a good faith effort. */static Lock iprintlock;static intiprintcanlock(Lock *l){	int i;		for(i=0; i<1000; i++){		if(canlock(l))			return 1;		if(l->m == MACHP(m->machno))			return 0;		microdelay(100);	}	return 0;} intiprint(char *fmt, ...){	int n, s, locked;	va_list arg;	char buf[PRINTSIZE]; 	s = splhi();	va_start(arg, fmt);	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg);	locked = iprintcanlock(&iprintlock);	if(screenputs != nil && iprintscreenputs)		screenputs(buf, n);	uartputs(buf, n);	if(locked)		unlock(&iprintlock);	splx(s); 	return n;} voidpanic(char *fmt, ...){	int s;	va_list arg;	char buf[PRINTSIZE]; 	kprintoq = nil;	/* don't try to write to /dev/kprint */ 	if(panicking)		for(;;);	panicking = 1; 	s = splhi();	strcpy(buf, "panic: ");	va_start(arg, fmt);	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);	va_end(arg);	iprint("%s\n", buf);	if(consdebug)		(*consdebug)();	splx(s);	prflush();	dumpstack(); 	/* reboot cpu servers and headless machines when not debugging */	if(getconf("*debug") == nil)	if(cpuserver || !conf.monitor)		exit(1); 	/* otherwise, just hang */	while(islo()) idlehands();	for(;;);} /* libmp at least contains a few calls to sysfatal; simulate with panic */voidsysfatal(char *fmt, ...){	char err[256];	va_list arg; 	va_start(arg, fmt);	vseprint(err, err + sizeof err, fmt, arg);	va_end(arg);	panic("sysfatal: %s", err);} void_assert(char *fmt){	panic("assert failed at %#p: %s", getcallerpc(&fmt), fmt);} intpprint(char *fmt, ...){	int n;	Chan *c;	va_list arg;	char buf[2*PRINTSIZE]; 	if(up == nil || up->fgrp == nil)		return 0; 	c = up->fgrp->fd[2];	if(c==nil || (c->mode!=OWRITE && c->mode!=ORDWR))		return 0;	n = snprint(buf, sizeof buf, "%s %lud: ", up->text, up->pid);	va_start(arg, fmt);	n = vseprint(buf+n, buf+sizeof(buf), fmt, arg) - buf;	va_end(arg); 	if(waserror())		return 0;	devtab[c->type]->write(c, buf, n, c->offset);	poperror(); 	lock(c);	c->offset += n;	unlock(c); 	return n;} enum{	Qdir,	Qbintime,	Qcons,	Qconsctl,	Qcputime,	Qdrivers,	Qkmesg,	Qkprint,	Qhostdomain,	Qhostowner,	Qnull,	Qosversion,	Qpgrpid,	Qpid,	Qppid,	Qrandom,	Qreboot,	Qswap,	Qsysname,	Qsysstat,	Qtime,	Quser,	Qzero,	Qmordor,	Qconfig,}; enum{	VLNUMSIZE=	22,}; static Dirtab consdir[]={	".",	{Qdir, 0, QTDIR},	0,		DMDIR|0555,	"bintime",	{Qbintime},	24,		0664,	"cons",		{Qcons},	0,		0660,	"consctl",	{Qconsctl},	0,		0220,	"cputime",	{Qcputime},	6*NUMSIZE,	0444,	"drivers",	{Qdrivers},	0,		0444,	"hostdomain",	{Qhostdomain},	DOMLEN,		0664,	"hostowner",	{Qhostowner},	0,		0664,	"kmesg",	{Qkmesg},	0,		0440,	"kprint",	{Qkprint, 0, QTEXCL},	0,	DMEXCL|0440,	"null",		{Qnull},	0,		0666,	"osversion",	{Qosversion},	0,		0444,	"pgrpid",	{Qpgrpid},	NUMSIZE,	0444,	"pid",		{Qpid},		NUMSIZE,	0444,	"ppid",		{Qppid},	NUMSIZE,	0444,	"random",	{Qrandom},	0,		0444,	"reboot",	{Qreboot},	0,		0664,	"swap",		{Qswap},	0,		0664,	"sysname",	{Qsysname},	0,		0664,	"sysstat",	{Qsysstat},	0,		0666,	"time",		{Qtime},	NUMSIZE+3*VLNUMSIZE,	0664,	"user",		{Quser},	0,		0666,	"zero",		{Qzero},	0,		0444,	"config",	{Qconfig},	0,		0444,	"mordor",	{Qmordor},	0,		0666,}; intreadnum(ulong off, char *buf, ulong n, ulong val, int size){	char tmp[64]; 	snprint(tmp, sizeof(tmp), "%*lud", size-1, val);	tmp[size-1] = ' ';	if(off >= size)		return 0;	if(off+n > size)		n = size-off;	memmove(buf, tmp+off, n);	return n;} intreadstr(ulong off, char *buf, ulong n, char *str){	int size; 	size = strlen(str);	if(off >= size)		return 0;	if(off+n > size)		n = size-off;	memmove(buf, str+off, n);	return n;} static voidconsinit(void){	todinit();	randominit();} static Chan*consattach(char *spec){	return devattach('c', spec);} static Walkqid*conswalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name,nname, consdir, nelem(consdir), devgen);} static intconsstat(Chan *c, uchar *dp, int n){	return devstat(c, dp, n, consdir, nelem(consdir), devgen);} static Chan*consopen(Chan *c, int omode){	c->aux = nil;	c = devopen(c, omode, consdir, nelem(consdir), devgen);	switch((ulong)c->qid.path){	case Qkprint:		if(tas(&kprintinuse) != 0){			c->flag &= ~COPEN;			error(Einuse);		}		if(kprintoq == nil){			kprintoq = qopen(8*1024, Qcoalesce, 0, 0);			if(kprintoq == nil){				c->flag &= ~COPEN;				error(Enomem);			}			qnoblock(kprintoq, 1);		}else			qreopen(kprintoq);		c->iounit = qiomaxatomic;		break;	}	return c;} static voidconsclose(Chan *c){	switch((ulong)c->qid.path){	/* close of kprint allows other opens */	case Qkprint:		if(c->flag & COPEN){			kprintinuse = 0;			qhangup(kprintoq, nil);		}		break;	}} static longconsread(Chan *c, void *buf, long n, vlong off){	ulong l;	Mach *mp;	char *b, *bp;	char tmp[256];		/* must be >= 18*NUMSIZE (Qswap) */	int i, k, id;	vlong offset = off;	extern char configfile[];	extern Image fscache;	extern Image swapimage; 	if(n <= 0)		return n; 	switch((ulong)c->qid.path){	case Qdir:		return devdirread(c, buf, n, consdir, nelem(consdir), devgen); 	case Qcons:		error(Egreg);

Lines 1–500 of 1069.