1607 lines · 28.6 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include	"u.h"#include	<trace.h>#include	"tos.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"ureg.h"#include	"../port/edf.h" enum{	Qdir,	Qtrace,	Qargs,	Qctl,	Qfd,	Qfpregs,	Qkregs,	Qmem,	Qnote,	Qnoteid,	Qnotepg,	Qns,	Qproc,	Qregs,	Qsegment,	Qstatus,	Qtext,	Qwait,	Qprofile,	Qsyscall,}; enum{	CMclose,	CMclosefiles,	CMfixedpri,	CMhang,	CMkill,	CMnohang,	CMnoswap,	CMpri,	CMprivate,	CMprofile,	CMstart,	CMstartstop,	CMstartsyscall,	CMstop,	CMwaitstop,	CMwired,	CMtrace,	/* real time */	CMperiod,	CMdeadline,	CMcost,	CMsporadic,	CMdeadlinenotes,	CMadmit,	CMextra,	CMexpel,	CMevent,}; enum{	Nevents = 0x4000,	Emask = Nevents - 1,}; #define	STATSIZE	(2*KNAMELEN+12+9*12)/* * Status, fd, and ns are left fully readable (0444) because of their use in debugging, * particularly on shared servers. * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 */Dirtab procdir[] ={	"args",		{Qargs},	0,			0660,	"ctl",		{Qctl},		0,			0000,	"fd",		{Qfd},		0,			0444,	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,	"kregs",	{Qkregs},	sizeof(Ureg),		0400,	"mem",		{Qmem},		0,			0000,	"note",		{Qnote},	0,			0000,	"noteid",	{Qnoteid},	0,			0664,	"notepg",	{Qnotepg},	0,			0000,	"ns",		{Qns},		0,			0444,	"proc",		{Qproc},	0,			0400,	"regs",		{Qregs},	sizeof(Ureg),		0000,	"segment",	{Qsegment},	0,			0444,	"status",	{Qstatus},	STATSIZE,		0444,	"text",		{Qtext},	0,			0000,	"wait",		{Qwait},	0,			0400,	"profile",	{Qprofile},	0,			0400,	"syscall",	{Qsyscall},	0,			0400,	}; staticCmdtab proccmd[] = {	CMclose,		"close",		2,	CMclosefiles,		"closefiles",		1,	CMfixedpri,		"fixedpri",		2,	CMhang,			"hang",			1,	CMnohang,		"nohang",		1,	CMnoswap,		"noswap",		1,	CMkill,			"kill",			1,	CMpri,			"pri",			2,	CMprivate,		"private",		1,	CMprofile,		"profile",		1,	CMstart,		"start",		1,	CMstartstop,		"startstop",		1,	CMstartsyscall,		"startsyscall",		1,	CMstop,			"stop",			1,	CMwaitstop,		"waitstop",		1,	CMwired,		"wired",		2,	CMtrace,		"trace",		0,	CMperiod,		"period",		2,	CMdeadline,		"deadline",		2,	CMcost,			"cost",			2,	CMsporadic,		"sporadic",		1,	CMdeadlinenotes,	"deadlinenotes",	1,	CMadmit,		"admit",		1,	CMextra,		"extra",		1,	CMexpel,		"expel",		1,	CMevent,		"event",		1,}; /* Segment type from portdat.h */static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", }; /* * Qids are, in path: *	 5 bits of file type (qids above) *	26 bits of process slot number + 1 *	     in vers, *	32 bits of pid, for consistency checking * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. */#define	QSHIFT	5	/* location in qid of proc slot # */ #define	QID(q)		((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)#define	SLOT(q)		(((((ulong)(q).path) & ~(1UL<<31)) >> QSHIFT) - 1)#define	PID(q)		((q).vers)#define	NOTEID(q)	((q).vers) void	procctlreq(Proc*, char*, int);int	procctlmemio(Proc*, ulong, int, void*, int);Chan*	proctext(Chan*, Proc*);Segment* txt2data(Proc*, Segment*);int	procstopped(void*);void	mntscan(Mntwalk*, Proc*); static Traceevent *tevents;static Lock tlock;static int topens;static int tproduced, tconsumed;void (*proctrace)(Proc*, int, vlong); extern int unfair; static voidprofclock(Ureg *ur, Timer *){	Tos *tos; 	if(up == 0 || up->state != Running)		return; 	/* user profiling clock */	if(userureg(ur)){		tos = (Tos*)(USTKTOP-sizeof(Tos));		tos->clock += TK2MS(1);		segclock(ur->pc);	}} static intprocgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp){	Qid qid;	Proc *p;	char *ename;	Segment *q;	ulong pid, path, perm, len; 	if(s == DEVDOTDOT){		mkqid(&qid, Qdir, 0, QTDIR);		devdir(c, qid, "#p", 0, eve, 0555, dp);		return 1;	} 	if(c->qid.path == Qdir){		if(s == 0){			strcpy(up->genbuf, "trace");			mkqid(&qid, Qtrace, -1, QTFILE);			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);			return 1;		} 		if(name != nil){			/* ignore s and use name to find pid */			pid = strtol(name, &ename, 10);			if(pid==0 || ename[0]!='\0')				return -1;			s = procindex(pid);			if(s < 0)				return -1;		}		else if(--s >= conf.nproc)			return -1; 		p = proctab(s);		pid = p->pid;		if(pid == 0)			return 0;		snprint(up->genbuf, sizeof up->genbuf, "%lud", pid);		/*		 * String comparison is done in devwalk so name must match its formatted pid		*/		if(name != nil && strcmp(name, up->genbuf) != 0)			return -1;		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);		return 1;	}	if(c->qid.path == Qtrace){		strcpy(up->genbuf, "trace");		mkqid(&qid, Qtrace, -1, QTFILE);		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);		return 1;	}	if(s >= nelem(procdir))		return -1;	if(tab)		panic("procgen"); 	tab = &procdir[s];	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */ 	/* p->procmode determines default mode for files in /proc */	p = proctab(SLOT(c->qid));	perm = tab->perm;	if(perm == 0)		perm = p->procmode;	else	/* just copy read bits */		perm |= p->procmode & 0444; 	len = tab->length;	switch(QID(c->qid)) {	case Qwait:		len = p->nwait;	/* incorrect size, but >0 means there's something to read */		break;	case Qprofile:		q = p->seg[TSEG];		if(q && q->profile) {			len = (q->top-q->base)>>LRESPROF;			len *= sizeof(*q->profile);		}		break;	} 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);	devdir(c, qid, tab->name, len, p->user, perm, dp);	return 1;} static void_proctrace(Proc* p, Tevent etype, vlong ts){	Traceevent *te; 	if (p->trace == 0 || topens == 0 ||		tproduced - tconsumed >= Nevents)		return; 	te = &tevents[tproduced&Emask];	te->pid = p->pid;	te->etype = etype;	if (ts == 0)		te->time = todget(nil);	else		te->time = ts;	tproduced++;} static voidprocinit(void){	if(conf.nproc >= (1<<(31-QSHIFT))-1)		print("warning: too many procs for devproc\n");	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */} static Chan*procattach(char *spec){	return devattach('p', spec);} static Walkqid*procwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, 0, 0, procgen);} static intprocstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, 0, 0, procgen);} /* *  none can't read or write state on other *  processes.  This is to contain access of *  servers running as none should they be *  subverted by, for example, a stack attack. */static voidnonone(Proc *p){	if(p == up)		return;	if(strcmp(up->user, "none") != 0)		return;	if(iseve())		return;	error(Eperm);} static Chan*procopen(Chan *c, int omode){	Proc *p;	Pgrp *pg;	Chan *tc;	int pid; 	if(c->qid.type & QTDIR)		return devopen(c, omode, 0, 0, procgen); 	if(QID(c->qid) == Qtrace){		if (omode != OREAD) 			error(Eperm);		lock(&tlock);		if (waserror()){			unlock(&tlock);			nexterror();		}		if (topens > 0)			error("already open");		topens++;		if (tevents == nil){			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);			if(tevents == nil)				error(Enomem);			tproduced = tconsumed = 0;		}		proctrace = _proctrace;		unlock(&tlock);		poperror(); 		c->mode = openmode(omode);		c->flag |= COPEN;		c->offset = 0;		return c;	}			p = proctab(SLOT(c->qid));	qlock(&p->debug);	if(waserror()){		qunlock(&p->debug);		nexterror();	}	pid = PID(c->qid);	if(p->pid != pid)		error(Eprocdied); 	omode = openmode(omode); 	switch(QID(c->qid)){	case Qtext:		if(omode != OREAD)			error(Eperm);		tc = proctext(c, p);		tc->offset = 0;		qunlock(&p->debug);		poperror();		cclose(c);		return tc; 	case Qproc:	case Qkregs:	case Qsegment:	case Qprofile:	case Qfd:		if(omode != OREAD)			error(Eperm);		break; 	case Qnote:		if(p->privatemem)			error(Eperm);		break; 	case Qmem:	case Qctl:		if(p->privatemem)			error(Eperm);		nonone(p);		break; 	case Qargs:	case Qnoteid:	case Qstatus:	case Qwait:	case Qregs:	case Qfpregs:	case Qsyscall:			nonone(p);		break; 	case Qns:		if(omode != OREAD)			error(Eperm);		c->aux = malloc(sizeof(Mntwalk));		break; 	case Qnotepg:		nonone(p);		pg = p->pgrp;		if(pg == nil)			error(Eprocdied);		if(omode!=OWRITE || pg->pgrpid == 1)			error(Eperm);		c->pgrpid.path = pg->pgrpid+1;		c->pgrpid.vers = p->noteid;		break; 	default:		pprint("procopen %#lux\n", QID(c->qid));		error(Egreg);	} 	/* Affix pid to qid */	if(p->state != Dead)		c->qid.vers = p->pid; 	/* make sure the process slot didn't get reallocated while we were playing */	coherence();	if(p->pid != pid)		error(Eprocdied); 	tc = devopen(c, omode, 0, 0, procgen);	qunlock(&p->debug);	poperror(); 	return tc;} static intprocwstat(Chan *c, uchar *db, int n){	Proc *p;	Dir *d; 	if(c->qid.type&QTDIR)		error(Eperm); 	if(QID(c->qid) == Qtrace)		return devwstat(c, db, n);			p = proctab(SLOT(c->qid));	nonone(p);	d = nil;	if(waserror()){		free(d);		qunlock(&p->debug);		nexterror();	}	qlock(&p->debug); 	if(p->pid != PID(c->qid))		error(Eprocdied); 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)		error(Eperm); 	d = smalloc(sizeof(Dir)+n);	n = convM2D(db, n, &d[0], (char*)&d[1]);

Lines 1–500 of 1607.