xref: /plan9-contrib/sys/src/9k/port/devproc.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier #include	"../port/edf.h"
99ef1f84bSDavid du Colombier #include	"tos.h"
109ef1f84bSDavid du Colombier #include	<trace.h>
119ef1f84bSDavid du Colombier #include	"ureg.h"
129ef1f84bSDavid du Colombier 
139ef1f84bSDavid du Colombier enum
149ef1f84bSDavid du Colombier {
159ef1f84bSDavid du Colombier 	Qdir,
169ef1f84bSDavid du Colombier 	Qtrace,
179ef1f84bSDavid du Colombier 	Qargs,
189ef1f84bSDavid du Colombier 	Qctl,
199ef1f84bSDavid du Colombier 	Qfd,
209ef1f84bSDavid du Colombier 	Qfpregs,
219ef1f84bSDavid du Colombier 	Qkregs,
229ef1f84bSDavid du Colombier 	Qmem,
239ef1f84bSDavid du Colombier 	Qnote,
249ef1f84bSDavid du Colombier 	Qnoteid,
259ef1f84bSDavid du Colombier 	Qnotepg,
269ef1f84bSDavid du Colombier 	Qns,
279ef1f84bSDavid du Colombier 	Qproc,
289ef1f84bSDavid du Colombier 	Qregs,
299ef1f84bSDavid du Colombier 	Qsegment,
309ef1f84bSDavid du Colombier 	Qstatus,
319ef1f84bSDavid du Colombier 	Qtext,
329ef1f84bSDavid du Colombier 	Qwait,
339ef1f84bSDavid du Colombier 	Qprofile,
349ef1f84bSDavid du Colombier 	Qsyscall,
359ef1f84bSDavid du Colombier };
369ef1f84bSDavid du Colombier 
379ef1f84bSDavid du Colombier enum
389ef1f84bSDavid du Colombier {
399ef1f84bSDavid du Colombier 	CMclose,
409ef1f84bSDavid du Colombier 	CMclosefiles,
419ef1f84bSDavid du Colombier 	CMfixedpri,
429ef1f84bSDavid du Colombier 	CMhang,
439ef1f84bSDavid du Colombier 	CMkill,
449ef1f84bSDavid du Colombier 	CMnohang,
459ef1f84bSDavid du Colombier 	CMnoswap,
469ef1f84bSDavid du Colombier 	CMpri,
479ef1f84bSDavid du Colombier 	CMprivate,
489ef1f84bSDavid du Colombier 	CMprofile,
499ef1f84bSDavid du Colombier 	CMstart,
509ef1f84bSDavid du Colombier 	CMstartstop,
519ef1f84bSDavid du Colombier 	CMstartsyscall,
529ef1f84bSDavid du Colombier 	CMstop,
539ef1f84bSDavid du Colombier 	CMwaitstop,
549ef1f84bSDavid du Colombier 	CMwired,
559ef1f84bSDavid du Colombier 	CMtrace,
569ef1f84bSDavid du Colombier 	/* real time */
579ef1f84bSDavid du Colombier 	CMperiod,
589ef1f84bSDavid du Colombier 	CMdeadline,
599ef1f84bSDavid du Colombier 	CMcost,
609ef1f84bSDavid du Colombier 	CMsporadic,
619ef1f84bSDavid du Colombier 	CMdeadlinenotes,
629ef1f84bSDavid du Colombier 	CMadmit,
639ef1f84bSDavid du Colombier 	CMextra,
649ef1f84bSDavid du Colombier 	CMexpel,
659ef1f84bSDavid du Colombier 	CMevent,
669ef1f84bSDavid du Colombier };
679ef1f84bSDavid du Colombier 
689ef1f84bSDavid du Colombier enum{
699ef1f84bSDavid du Colombier 	Nevents = 0x4000,
709ef1f84bSDavid du Colombier 	Emask = Nevents - 1,
719ef1f84bSDavid du Colombier };
729ef1f84bSDavid du Colombier 
739ef1f84bSDavid du Colombier #define STATSIZE	(2*KNAMELEN+12+9*12)
749ef1f84bSDavid du Colombier /*
759ef1f84bSDavid du Colombier  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
769ef1f84bSDavid du Colombier  * particularly on shared servers.
779ef1f84bSDavid du Colombier  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
789ef1f84bSDavid du Colombier  */
799ef1f84bSDavid du Colombier Dirtab procdir[] =
809ef1f84bSDavid du Colombier {
819ef1f84bSDavid du Colombier 	"args",		{Qargs},	0,			0660,
829ef1f84bSDavid du Colombier 	"ctl",		{Qctl},		0,			0000,
839ef1f84bSDavid du Colombier 	"fd",		{Qfd},		0,			0444,
849ef1f84bSDavid du Colombier 	"fpregs",	{Qfpregs},	0,			0000,
859ef1f84bSDavid du Colombier 	"kregs",	{Qkregs},	sizeof(Ureg),		0400,
869ef1f84bSDavid du Colombier 	"mem",		{Qmem},		0,			0000,
879ef1f84bSDavid du Colombier 	"note",		{Qnote},	0,			0000,
889ef1f84bSDavid du Colombier 	"noteid",	{Qnoteid},	0,			0664,
899ef1f84bSDavid du Colombier 	"notepg",	{Qnotepg},	0,			0000,
909ef1f84bSDavid du Colombier 	"ns",		{Qns},		0,			0444,
919ef1f84bSDavid du Colombier 	"proc",		{Qproc},	0,			0400,
929ef1f84bSDavid du Colombier 	"regs",		{Qregs},	sizeof(Ureg),		0000,
939ef1f84bSDavid du Colombier 	"segment",	{Qsegment},	0,			0444,
949ef1f84bSDavid du Colombier 	"status",	{Qstatus},	STATSIZE,		0444,
959ef1f84bSDavid du Colombier 	"text",		{Qtext},	0,			0000,
969ef1f84bSDavid du Colombier 	"wait",		{Qwait},	0,			0400,
979ef1f84bSDavid du Colombier 	"profile",	{Qprofile},	0,			0400,
989ef1f84bSDavid du Colombier 	"syscall",	{Qsyscall},	0,			0400,
999ef1f84bSDavid du Colombier };
1009ef1f84bSDavid du Colombier 
1019ef1f84bSDavid du Colombier static
1029ef1f84bSDavid du Colombier Cmdtab proccmd[] = {
1039ef1f84bSDavid du Colombier 	CMclose,		"close",		2,
1049ef1f84bSDavid du Colombier 	CMclosefiles,		"closefiles",		1,
1059ef1f84bSDavid du Colombier 	CMfixedpri,		"fixedpri",		2,
1069ef1f84bSDavid du Colombier 	CMhang,			"hang",			1,
1079ef1f84bSDavid du Colombier 	CMnohang,		"nohang",		1,
1089ef1f84bSDavid du Colombier 	CMnoswap,		"noswap",		1,
1099ef1f84bSDavid du Colombier 	CMkill,			"kill",			1,
1109ef1f84bSDavid du Colombier 	CMpri,			"pri",			2,
1119ef1f84bSDavid du Colombier 	CMprivate,		"private",		1,
1129ef1f84bSDavid du Colombier 	CMprofile,		"profile",		1,
1139ef1f84bSDavid du Colombier 	CMstart,		"start",		1,
1149ef1f84bSDavid du Colombier 	CMstartstop,		"startstop",		1,
1159ef1f84bSDavid du Colombier 	CMstartsyscall,		"startsyscall",		1,
1169ef1f84bSDavid du Colombier 	CMstop,			"stop",			1,
1179ef1f84bSDavid du Colombier 	CMwaitstop,		"waitstop",		1,
1189ef1f84bSDavid du Colombier 	CMwired,		"wired",		2,
1199ef1f84bSDavid du Colombier 	CMtrace,		"trace",		0,
1209ef1f84bSDavid du Colombier 	CMperiod,		"period",		2,
1219ef1f84bSDavid du Colombier 	CMdeadline,		"deadline",		2,
1229ef1f84bSDavid du Colombier 	CMcost,			"cost",			2,
1239ef1f84bSDavid du Colombier 	CMsporadic,		"sporadic",		1,
1249ef1f84bSDavid du Colombier 	CMdeadlinenotes,	"deadlinenotes",	1,
1259ef1f84bSDavid du Colombier 	CMadmit,		"admit",		1,
1269ef1f84bSDavid du Colombier 	CMextra,		"extra",		1,
1279ef1f84bSDavid du Colombier 	CMexpel,		"expel",		1,
1289ef1f84bSDavid du Colombier 	CMevent,		"event",		1,
1299ef1f84bSDavid du Colombier };
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier /* Segment type from portdat.h */
1329ef1f84bSDavid du Colombier static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
1339ef1f84bSDavid du Colombier 
1349ef1f84bSDavid du Colombier /*
1359ef1f84bSDavid du Colombier  * Qids are, in path:
136406c76faSDavid du Colombier  *	 5 bits of file type (qids above)
137406c76faSDavid du Colombier  *	26 bits of process slot number + 1
1389ef1f84bSDavid du Colombier  *	     in vers,
1399ef1f84bSDavid du Colombier  *	32 bits of pid, for consistency checking
1409ef1f84bSDavid du Colombier  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
1419ef1f84bSDavid du Colombier  */
1429ef1f84bSDavid du Colombier #define QSHIFT	5	/* location in qid of proc slot # */
1439ef1f84bSDavid du Colombier 
144406c76faSDavid du Colombier #define QID(q)		((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)
145406c76faSDavid du Colombier #define SLOT(q)		(((((ulong)(q).path) & ~(1UL<<31)) >> QSHIFT) - 1)
1469ef1f84bSDavid du Colombier #define PID(q)		((q).vers)
1479ef1f84bSDavid du Colombier #define NOTEID(q)	((q).vers)
1489ef1f84bSDavid du Colombier 
1499ef1f84bSDavid du Colombier static void	procctlreq(Proc*, char*, int);
1509ef1f84bSDavid du Colombier static int	procctlmemio(Proc*, uintptr, int, void*, int);
1519ef1f84bSDavid du Colombier static Chan*	proctext(Chan*, Proc*);
1529ef1f84bSDavid du Colombier static Segment* txt2data(Proc*, Segment*);
1539ef1f84bSDavid du Colombier static int	procstopped(void*);
1549ef1f84bSDavid du Colombier static void	mntscan(Mntwalk*, Proc*);
1559ef1f84bSDavid du Colombier 
1569ef1f84bSDavid du Colombier static Traceevent *tevents;
1579ef1f84bSDavid du Colombier static Lock tlock;
1589ef1f84bSDavid du Colombier static int topens;
1599ef1f84bSDavid du Colombier static int tproduced, tconsumed;
1609ef1f84bSDavid du Colombier 
1619ef1f84bSDavid du Colombier static void
profclock(Ureg * ur,Timer *)1629ef1f84bSDavid du Colombier profclock(Ureg *ur, Timer *)
1639ef1f84bSDavid du Colombier {
1649ef1f84bSDavid du Colombier 	Tos *tos;
1659ef1f84bSDavid du Colombier 
1669ef1f84bSDavid du Colombier 	if(up == nil || up->state != Running)
1679ef1f84bSDavid du Colombier 		return;
1689ef1f84bSDavid du Colombier 
1699ef1f84bSDavid du Colombier 	/* user profiling clock */
1709ef1f84bSDavid du Colombier 	if(userureg(ur)){
1719ef1f84bSDavid du Colombier 		tos = (Tos*)(USTKTOP-sizeof(Tos));
1729ef1f84bSDavid du Colombier 		tos->clock += TK2MS(1);
1739ef1f84bSDavid du Colombier 		segclock(userpc(ur));
1749ef1f84bSDavid du Colombier 	}
1759ef1f84bSDavid du Colombier }
1769ef1f84bSDavid du Colombier 
1779ef1f84bSDavid du Colombier static int
procgen(Chan * c,char * name,Dirtab * tab,int,int s,Dir * dp)1789ef1f84bSDavid du Colombier procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
1799ef1f84bSDavid du Colombier {
1809ef1f84bSDavid du Colombier 	Qid qid;
1819ef1f84bSDavid du Colombier 	Proc *p;
1829ef1f84bSDavid du Colombier 	char *ename;
1839ef1f84bSDavid du Colombier 	Segment *q;
1849ef1f84bSDavid du Colombier 	int pid;
1859ef1f84bSDavid du Colombier 	ulong path, perm, len;
1869ef1f84bSDavid du Colombier 
1879ef1f84bSDavid du Colombier 	if(s == DEVDOTDOT){
1889ef1f84bSDavid du Colombier 		mkqid(&qid, Qdir, 0, QTDIR);
1899ef1f84bSDavid du Colombier 		devdir(c, qid, "#p", 0, eve, 0555, dp);
1909ef1f84bSDavid du Colombier 		return 1;
1919ef1f84bSDavid du Colombier 	}
1929ef1f84bSDavid du Colombier 
1939ef1f84bSDavid du Colombier 	if(c->qid.path == Qdir){
1949ef1f84bSDavid du Colombier 		if(s == 0){
1959ef1f84bSDavid du Colombier 			strcpy(up->genbuf, "trace");
1969ef1f84bSDavid du Colombier 			mkqid(&qid, Qtrace, -1, QTFILE);
1979ef1f84bSDavid du Colombier 			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
1989ef1f84bSDavid du Colombier 			return 1;
1999ef1f84bSDavid du Colombier 		}
2009ef1f84bSDavid du Colombier 
2019ef1f84bSDavid du Colombier 		if(name != nil){
2029ef1f84bSDavid du Colombier 			/* ignore s and use name to find pid */
2039ef1f84bSDavid du Colombier 			pid = strtol(name, &ename, 10);
2049ef1f84bSDavid du Colombier 			if(pid<=0 || ename[0]!='\0')
2059ef1f84bSDavid du Colombier 				return -1;
2069ef1f84bSDavid du Colombier 			s = psindex(pid);
2079ef1f84bSDavid du Colombier 			if(s < 0)
2089ef1f84bSDavid du Colombier 				return -1;
2099ef1f84bSDavid du Colombier 		}
2109ef1f84bSDavid du Colombier 		else if(--s >= PROCMAX)
2119ef1f84bSDavid du Colombier 			return -1;
2129ef1f84bSDavid du Colombier 
2139ef1f84bSDavid du Colombier 		if((p = psincref(s)) == nil || (pid = p->pid) == 0)
2149ef1f84bSDavid du Colombier 			return 0;
215406c76faSDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "%d", pid);
2169ef1f84bSDavid du Colombier 		/*
2179ef1f84bSDavid du Colombier 		 * String comparison is done in devwalk so
2189ef1f84bSDavid du Colombier 		 * name must match its formatted pid.
2199ef1f84bSDavid du Colombier 		 */
2209ef1f84bSDavid du Colombier 		if(name != nil && strcmp(name, up->genbuf) != 0)
2219ef1f84bSDavid du Colombier 			return -1;
2229ef1f84bSDavid du Colombier 		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
2239ef1f84bSDavid du Colombier 		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
2249ef1f84bSDavid du Colombier 		psdecref(p);
2259ef1f84bSDavid du Colombier 		return 1;
2269ef1f84bSDavid du Colombier 	}
2279ef1f84bSDavid du Colombier 	if(c->qid.path == Qtrace){
2289ef1f84bSDavid du Colombier 		strcpy(up->genbuf, "trace");
2299ef1f84bSDavid du Colombier 		mkqid(&qid, Qtrace, -1, QTFILE);
2309ef1f84bSDavid du Colombier 		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
2319ef1f84bSDavid du Colombier 		return 1;
2329ef1f84bSDavid du Colombier 	}
2339ef1f84bSDavid du Colombier 	if(s >= nelem(procdir))
2349ef1f84bSDavid du Colombier 		return -1;
2359ef1f84bSDavid du Colombier 	if(tab)
2369ef1f84bSDavid du Colombier 		panic("procgen");
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier 	tab = &procdir[s];
2399ef1f84bSDavid du Colombier 	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
2409ef1f84bSDavid du Colombier 
241406c76faSDavid du Colombier 	/* p->procmode determines default mode for files in /proc */
2429ef1f84bSDavid du Colombier 	if((p = psincref(SLOT(c->qid))) == nil)
2439ef1f84bSDavid du Colombier 		return -1;
2449ef1f84bSDavid du Colombier 	perm = tab->perm;
2459ef1f84bSDavid du Colombier 	if(perm == 0)
2469ef1f84bSDavid du Colombier 		perm = p->procmode;
2479ef1f84bSDavid du Colombier 	else	/* just copy read bits */
2489ef1f84bSDavid du Colombier 		perm |= p->procmode & 0444;
2499ef1f84bSDavid du Colombier 
2509ef1f84bSDavid du Colombier 	len = tab->length;
2519ef1f84bSDavid du Colombier 	switch(QID(c->qid)) {
2529ef1f84bSDavid du Colombier 	case Qwait:
2539ef1f84bSDavid du Colombier 		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
2549ef1f84bSDavid du Colombier 		break;
2559ef1f84bSDavid du Colombier 	case Qprofile:
2569ef1f84bSDavid du Colombier 		q = p->seg[TSEG];
2579ef1f84bSDavid du Colombier 		if(q && q->profile) {
2589ef1f84bSDavid du Colombier 			len = (q->top-q->base)>>LRESPROF;
2599ef1f84bSDavid du Colombier 			len *= sizeof(*q->profile);
2609ef1f84bSDavid du Colombier 		}
2619ef1f84bSDavid du Colombier 		break;
2629ef1f84bSDavid du Colombier 	}
2639ef1f84bSDavid du Colombier 
2649ef1f84bSDavid du Colombier 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
2659ef1f84bSDavid du Colombier 	devdir(c, qid, tab->name, len, p->user, perm, dp);
2669ef1f84bSDavid du Colombier 	psdecref(p);
2679ef1f84bSDavid du Colombier 	return 1;
2689ef1f84bSDavid du Colombier }
2699ef1f84bSDavid du Colombier 
2709ef1f84bSDavid du Colombier static void
_proctrace(Proc * p,Tevent etype,vlong ts,vlong)271d46407a3SDavid du Colombier _proctrace(Proc* p, Tevent etype, vlong ts, vlong)
2729ef1f84bSDavid du Colombier {
2739ef1f84bSDavid du Colombier 	Traceevent *te;
2749ef1f84bSDavid du Colombier 
2759ef1f84bSDavid du Colombier 	if (p->trace == 0 || topens == 0 ||
2769ef1f84bSDavid du Colombier 		tproduced - tconsumed >= Nevents)
2779ef1f84bSDavid du Colombier 		return;
2789ef1f84bSDavid du Colombier 
2799ef1f84bSDavid du Colombier 	te = &tevents[tproduced&Emask];
2809ef1f84bSDavid du Colombier 	te->pid = p->pid;
2819ef1f84bSDavid du Colombier 	te->etype = etype;
2829ef1f84bSDavid du Colombier 	if (ts == 0)
2839ef1f84bSDavid du Colombier 		te->time = todget(nil);
2849ef1f84bSDavid du Colombier 	else
2859ef1f84bSDavid du Colombier 		te->time = ts;
2869ef1f84bSDavid du Colombier 	tproduced++;
2879ef1f84bSDavid du Colombier }
2889ef1f84bSDavid du Colombier 
2899ef1f84bSDavid du Colombier static void
procinit(void)2909ef1f84bSDavid du Colombier procinit(void)
2919ef1f84bSDavid du Colombier {
292406c76faSDavid du Colombier 	if(PROCMAX >= (1<<(31-QSHIFT))-1)
2939ef1f84bSDavid du Colombier 		print("warning: too many procs for devproc\n");
2949ef1f84bSDavid du Colombier 	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier static Chan*
procattach(char * spec)2989ef1f84bSDavid du Colombier procattach(char *spec)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier 	return devattach('p', spec);
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier 
3039ef1f84bSDavid du Colombier static Walkqid*
procwalk(Chan * c,Chan * nc,char ** name,int nname)3049ef1f84bSDavid du Colombier procwalk(Chan *c, Chan *nc, char **name, int nname)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, procgen);
3079ef1f84bSDavid du Colombier }
3089ef1f84bSDavid du Colombier 
3099ef1f84bSDavid du Colombier static long
procstat(Chan * c,uchar * db,long n)3109ef1f84bSDavid du Colombier procstat(Chan *c, uchar *db, long n)
3119ef1f84bSDavid du Colombier {
3129ef1f84bSDavid du Colombier 	return devstat(c, db, n, 0, 0, procgen);
3139ef1f84bSDavid du Colombier }
3149ef1f84bSDavid du Colombier 
3159ef1f84bSDavid du Colombier /*
3169ef1f84bSDavid du Colombier  *  none can't read or write state on other
3179ef1f84bSDavid du Colombier  *  processes.  This is to contain access of
3189ef1f84bSDavid du Colombier  *  servers running as none should they be
3199ef1f84bSDavid du Colombier  *  subverted by, for example, a stack attack.
3209ef1f84bSDavid du Colombier  */
3219ef1f84bSDavid du Colombier static void
nonone(Proc * p)3229ef1f84bSDavid du Colombier nonone(Proc *p)
3239ef1f84bSDavid du Colombier {
3249ef1f84bSDavid du Colombier 	if(p == up)
3259ef1f84bSDavid du Colombier 		return;
3269ef1f84bSDavid du Colombier 	if(strcmp(up->user, "none") != 0)
3279ef1f84bSDavid du Colombier 		return;
3289ef1f84bSDavid du Colombier 	if(iseve())
3299ef1f84bSDavid du Colombier 		return;
3309ef1f84bSDavid du Colombier 	error(Eperm);
3319ef1f84bSDavid du Colombier }
3329ef1f84bSDavid du Colombier 
3339ef1f84bSDavid du Colombier static Chan*
procopen(Chan * c,int omode)3349ef1f84bSDavid du Colombier procopen(Chan *c, int omode)
3359ef1f84bSDavid du Colombier {
3369ef1f84bSDavid du Colombier 	Proc *p;
3379ef1f84bSDavid du Colombier 	Pgrp *pg;
3389ef1f84bSDavid du Colombier 	Chan *tc;
3399ef1f84bSDavid du Colombier 	int pid;
3409ef1f84bSDavid du Colombier 
3419ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
3429ef1f84bSDavid du Colombier 		return devopen(c, omode, 0, 0, procgen);
3439ef1f84bSDavid du Colombier 
3449ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qtrace){
3459ef1f84bSDavid du Colombier 		if (omode != OREAD)
3469ef1f84bSDavid du Colombier 			error(Eperm);
3479ef1f84bSDavid du Colombier 		lock(&tlock);
3489ef1f84bSDavid du Colombier 		if (waserror()){
3499ef1f84bSDavid du Colombier 			unlock(&tlock);
3509ef1f84bSDavid du Colombier 			nexterror();
3519ef1f84bSDavid du Colombier 		}
3529ef1f84bSDavid du Colombier 		if (topens > 0)
3539ef1f84bSDavid du Colombier 			error("already open");
3549ef1f84bSDavid du Colombier 		topens++;
3559ef1f84bSDavid du Colombier 		if (tevents == nil){
3569ef1f84bSDavid du Colombier 			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
3579ef1f84bSDavid du Colombier 			if(tevents == nil)
3589ef1f84bSDavid du Colombier 				error(Enomem);
3599ef1f84bSDavid du Colombier 			tproduced = tconsumed = 0;
3609ef1f84bSDavid du Colombier 		}
3619ef1f84bSDavid du Colombier 		proctrace = _proctrace;
3629ef1f84bSDavid du Colombier 		poperror();
3639ef1f84bSDavid du Colombier 		unlock(&tlock);
3649ef1f84bSDavid du Colombier 
3659ef1f84bSDavid du Colombier 		c->mode = openmode(omode);
3669ef1f84bSDavid du Colombier 		c->flag |= COPEN;
3679ef1f84bSDavid du Colombier 		c->offset = 0;
3689ef1f84bSDavid du Colombier 		return c;
3699ef1f84bSDavid du Colombier 	}
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier 	if((p = psincref(SLOT(c->qid))) == nil)
3729ef1f84bSDavid du Colombier 		error(Eprocdied);
3739ef1f84bSDavid du Colombier 	qlock(&p->debug);
3749ef1f84bSDavid du Colombier 	if(waserror()){
3759ef1f84bSDavid du Colombier 		qunlock(&p->debug);
3769ef1f84bSDavid du Colombier 		psdecref(p);
3779ef1f84bSDavid du Colombier 		nexterror();
3789ef1f84bSDavid du Colombier 	}
3799ef1f84bSDavid du Colombier 	pid = PID(c->qid);
3809ef1f84bSDavid du Colombier 	if(p->pid != pid)
3819ef1f84bSDavid du Colombier 		error(Eprocdied);
3829ef1f84bSDavid du Colombier 
3839ef1f84bSDavid du Colombier 	omode = openmode(omode);
3849ef1f84bSDavid du Colombier 
3859ef1f84bSDavid du Colombier 	switch(QID(c->qid)){
3869ef1f84bSDavid du Colombier 	case Qtext:
3879ef1f84bSDavid du Colombier 		if(omode != OREAD)
3889ef1f84bSDavid du Colombier 			error(Eperm);
3899ef1f84bSDavid du Colombier 		tc = proctext(c, p);
3909ef1f84bSDavid du Colombier 		tc->offset = 0;
3919ef1f84bSDavid du Colombier 		poperror();
392406c76faSDavid du Colombier 		cclose(c);
3939ef1f84bSDavid du Colombier 		qunlock(&p->debug);
3949ef1f84bSDavid du Colombier 		psdecref(p);
3959ef1f84bSDavid du Colombier 		return tc;
3969ef1f84bSDavid du Colombier 
3979ef1f84bSDavid du Colombier 	case Qproc:
3989ef1f84bSDavid du Colombier 	case Qkregs:
3999ef1f84bSDavid du Colombier 	case Qsegment:
4009ef1f84bSDavid du Colombier 	case Qprofile:
4019ef1f84bSDavid du Colombier 	case Qfd:
4029ef1f84bSDavid du Colombier 		if(omode != OREAD)
4039ef1f84bSDavid du Colombier 			error(Eperm);
4049ef1f84bSDavid du Colombier 		break;
4059ef1f84bSDavid du Colombier 
4069ef1f84bSDavid du Colombier 	case Qnote:
4079ef1f84bSDavid du Colombier 		if(p->privatemem)
4089ef1f84bSDavid du Colombier 			error(Eperm);
4099ef1f84bSDavid du Colombier 		break;
4109ef1f84bSDavid du Colombier 
4119ef1f84bSDavid du Colombier 	case Qmem:
4129ef1f84bSDavid du Colombier 	case Qctl:
4139ef1f84bSDavid du Colombier 		if(p->privatemem)
4149ef1f84bSDavid du Colombier 			error(Eperm);
4159ef1f84bSDavid du Colombier 		nonone(p);
4169ef1f84bSDavid du Colombier 		break;
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 	case Qargs:
4199ef1f84bSDavid du Colombier 	case Qnoteid:
4209ef1f84bSDavid du Colombier 	case Qstatus:
4219ef1f84bSDavid du Colombier 	case Qwait:
4229ef1f84bSDavid du Colombier 	case Qregs:
4239ef1f84bSDavid du Colombier 	case Qfpregs:
4249ef1f84bSDavid du Colombier 	case Qsyscall:
4259ef1f84bSDavid du Colombier 		nonone(p);
4269ef1f84bSDavid du Colombier 		break;
4279ef1f84bSDavid du Colombier 
4289ef1f84bSDavid du Colombier 	case Qns:
4299ef1f84bSDavid du Colombier 		if(omode != OREAD)
4309ef1f84bSDavid du Colombier 			error(Eperm);
4319ef1f84bSDavid du Colombier 		c->aux = malloc(sizeof(Mntwalk));
4329ef1f84bSDavid du Colombier 		break;
4339ef1f84bSDavid du Colombier 
4349ef1f84bSDavid du Colombier 	case Qnotepg:
4359ef1f84bSDavid du Colombier 		nonone(p);
4369ef1f84bSDavid du Colombier 		pg = p->pgrp;
4379ef1f84bSDavid du Colombier 		if(pg == nil)
4389ef1f84bSDavid du Colombier 			error(Eprocdied);
4399ef1f84bSDavid du Colombier 		if(omode!=OWRITE || pg->pgrpid == 1)
4409ef1f84bSDavid du Colombier 			error(Eperm);
4419ef1f84bSDavid du Colombier 		c->pgrpid.path = pg->pgrpid+1;
4429ef1f84bSDavid du Colombier 		c->pgrpid.vers = p->noteid;
4439ef1f84bSDavid du Colombier 		break;
4449ef1f84bSDavid du Colombier 
4459ef1f84bSDavid du Colombier 	default:
4469ef1f84bSDavid du Colombier 		poperror();
4479ef1f84bSDavid du Colombier 		qunlock(&p->debug);
4489ef1f84bSDavid du Colombier 		psdecref(p);
4499ef1f84bSDavid du Colombier 		pprint("procopen %#llux\n", c->qid.path);
4509ef1f84bSDavid du Colombier 		error(Egreg);
4519ef1f84bSDavid du Colombier 	}
4529ef1f84bSDavid du Colombier 
4539ef1f84bSDavid du Colombier 	/* Affix pid to qid */
4549ef1f84bSDavid du Colombier 	if(p->state != Dead)
4559ef1f84bSDavid du Colombier 		c->qid.vers = p->pid;
4569ef1f84bSDavid du Colombier 
4579ef1f84bSDavid du Colombier 	/* make sure the process slot didn't get reallocated while we were playing */
4589ef1f84bSDavid du Colombier 	coherence();
4599ef1f84bSDavid du Colombier 	if(p->pid != pid)
4609ef1f84bSDavid du Colombier 		error(Eprocdied);
4619ef1f84bSDavid du Colombier 
4629ef1f84bSDavid du Colombier 	tc = devopen(c, omode, 0, 0, procgen);
4639ef1f84bSDavid du Colombier 	poperror();
4649ef1f84bSDavid du Colombier 	qunlock(&p->debug);
4659ef1f84bSDavid du Colombier 	psdecref(p);
4669ef1f84bSDavid du Colombier 
4679ef1f84bSDavid du Colombier 	return tc;
4689ef1f84bSDavid du Colombier }
4699ef1f84bSDavid du Colombier 
4709ef1f84bSDavid du Colombier static long
procwstat(Chan * c,uchar * db,long n)4719ef1f84bSDavid du Colombier procwstat(Chan *c, uchar *db, long n)
4729ef1f84bSDavid du Colombier {
4739ef1f84bSDavid du Colombier 	Proc *p;
4749ef1f84bSDavid du Colombier 	Dir *d;
4759ef1f84bSDavid du Colombier 
4769ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
4779ef1f84bSDavid du Colombier 		error(Eperm);
4789ef1f84bSDavid du Colombier 
4799ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qtrace)
4809ef1f84bSDavid du Colombier 		return devwstat(c, db, n);
4819ef1f84bSDavid du Colombier 
4829ef1f84bSDavid du Colombier 	if((p = psincref(SLOT(c->qid))) == nil)
4839ef1f84bSDavid du Colombier 		error(Eprocdied);
4849ef1f84bSDavid du Colombier 	nonone(p);
4859ef1f84bSDavid du Colombier 	d = nil;
4869ef1f84bSDavid du Colombier 	qlock(&p->debug);
4879ef1f84bSDavid du Colombier 	if(waserror()){
4889ef1f84bSDavid du Colombier 		qunlock(&p->debug);
4899ef1f84bSDavid du Colombier 		psdecref(p);
4909ef1f84bSDavid du Colombier 		free(d);
4919ef1f84bSDavid du Colombier 		nexterror();
4929ef1f84bSDavid du Colombier 	}
4939ef1f84bSDavid du Colombier 
4949ef1f84bSDavid du Colombier 	if(p->pid != PID(c->qid))
4959ef1f84bSDavid du Colombier 		error(Eprocdied);
4969ef1f84bSDavid du Colombier 
4979ef1f84bSDavid du Colombier 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
4989ef1f84bSDavid du Colombier 		error(Eperm);
4999ef1f84bSDavid du Colombier 
5009ef1f84bSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
5019ef1f84bSDavid du Colombier 	n = convM2D(db, n, &d[0], (char*)&d[1]);
5029ef1f84bSDavid du Colombier 	if(n == 0)
5039ef1f84bSDavid du Colombier 		error(Eshortstat);
5049ef1f84bSDavid du Colombier 	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
5059ef1f84bSDavid du Colombier 		if(strcmp(up->user, eve) != 0)
5069ef1f84bSDavid du Colombier 			error(Eperm);
5079ef1f84bSDavid du Colombier 		else
5089ef1f84bSDavid du Colombier 			kstrdup(&p->user, d->uid);
5099ef1f84bSDavid du Colombier 	}
510406c76faSDavid du Colombier 	/* p->procmode determines default mode for files in /proc */
5119ef1f84bSDavid du Colombier 	if(d->mode != ~0UL)
5129ef1f84bSDavid du Colombier 		p->procmode = d->mode&0777;
5139ef1f84bSDavid du Colombier 
5149ef1f84bSDavid du Colombier 	poperror();
5159ef1f84bSDavid du Colombier 	qunlock(&p->debug);
5169ef1f84bSDavid du Colombier 	psdecref(p);
5179ef1f84bSDavid du Colombier 	free(d);
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 	return n;
5209ef1f84bSDavid du Colombier }
5219ef1f84bSDavid du Colombier 
5229ef1f84bSDavid du Colombier 
5239ef1f84bSDavid du Colombier static long
procoffset(long offset,char * va,int * np)5249ef1f84bSDavid du Colombier procoffset(long offset, char *va, int *np)
5259ef1f84bSDavid du Colombier {
5269ef1f84bSDavid du Colombier 	if(offset > 0) {
5279ef1f84bSDavid du Colombier 		offset -= *np;
5289ef1f84bSDavid du Colombier 		if(offset < 0) {
5299ef1f84bSDavid du Colombier 			memmove(va, va+*np+offset, -offset);
5309ef1f84bSDavid du Colombier 			*np = -offset;
5319ef1f84bSDavid du Colombier 		}
5329ef1f84bSDavid du Colombier 		else
5339ef1f84bSDavid du Colombier 			*np = 0;
5349ef1f84bSDavid du Colombier 	}
5359ef1f84bSDavid du Colombier 	return offset;
5369ef1f84bSDavid du Colombier }
5379ef1f84bSDavid du Colombier 
5389ef1f84bSDavid du Colombier static int
procqidwidth(Chan * c)5399ef1f84bSDavid du Colombier procqidwidth(Chan *c)
5409ef1f84bSDavid du Colombier {
5419ef1f84bSDavid du Colombier 	char buf[32];
5429ef1f84bSDavid du Colombier 
543406c76faSDavid du Colombier 	return snprint(buf, sizeof buf, "%lud", c->qid.vers);
5449ef1f84bSDavid du Colombier }
5459ef1f84bSDavid du Colombier 
5469ef1f84bSDavid du Colombier int
procfdprint(Chan * c,int fd,int w,char * s,int ns)5479ef1f84bSDavid du Colombier procfdprint(Chan *c, int fd, int w, char *s, int ns)
5489ef1f84bSDavid du Colombier {
5499ef1f84bSDavid du Colombier 	int n;
5509ef1f84bSDavid du Colombier 
5519ef1f84bSDavid du Colombier 	if(w == 0)
5529ef1f84bSDavid du Colombier 		w = procqidwidth(c);
5539ef1f84bSDavid du Colombier 	n = snprint(s, ns, "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
5549ef1f84bSDavid du Colombier 		fd,
5559ef1f84bSDavid du Colombier 		&"r w rw"[(c->mode&3)<<1],
5569ef1f84bSDavid du Colombier 		c->dev->dc, c->devno,
5579ef1f84bSDavid du Colombier 		c->qid.path, w, c->qid.vers, c->qid.type,
5589ef1f84bSDavid du Colombier 		c->iounit, c->offset, c->path->s);
5599ef1f84bSDavid du Colombier 	return n;
5609ef1f84bSDavid du Colombier }
5619ef1f84bSDavid du Colombier 
5629ef1f84bSDavid du Colombier static int
procfds(Proc * p,char * va,int count,long offset)5639ef1f84bSDavid du Colombier procfds(Proc *p, char *va, int count, long offset)
5649ef1f84bSDavid du Colombier {
5659ef1f84bSDavid du Colombier 	Fgrp *f;
5669ef1f84bSDavid du Colombier 	Chan *c;
5679ef1f84bSDavid du Colombier 	char buf[256];
5689ef1f84bSDavid du Colombier 	int n, i, w, ww;
5699ef1f84bSDavid du Colombier 	char *a;
5709ef1f84bSDavid du Colombier 
5719ef1f84bSDavid du Colombier 	/* print to buf to avoid holding fgrp lock while writing to user space */
5729ef1f84bSDavid du Colombier 	if(count > sizeof buf)
5739ef1f84bSDavid du Colombier 		count = sizeof buf;
5749ef1f84bSDavid du Colombier 	a = buf;
5759ef1f84bSDavid du Colombier 
5769ef1f84bSDavid du Colombier 	qlock(&p->debug);
5779ef1f84bSDavid du Colombier 	f = p->fgrp;
5789ef1f84bSDavid du Colombier 	if(f == nil){
5799ef1f84bSDavid du Colombier 		qunlock(&p->debug);
5809ef1f84bSDavid du Colombier 		return 0;
5819ef1f84bSDavid du Colombier 	}
5829ef1f84bSDavid du Colombier 	lock(f);
5839ef1f84bSDavid du Colombier 	if(waserror()){
5849ef1f84bSDavid du Colombier 		unlock(f);
5859ef1f84bSDavid du Colombier 		qunlock(&p->debug);
5869ef1f84bSDavid du Colombier 		nexterror();
5879ef1f84bSDavid du Colombier 	}
5889ef1f84bSDavid du Colombier 
5899ef1f84bSDavid du Colombier 	n = readstr(0, a, count, p->dot->path->s);
5909ef1f84bSDavid du Colombier 	n += snprint(a+n, count-n, "\n");
5919ef1f84bSDavid du Colombier 	offset = procoffset(offset, a, &n);
5929ef1f84bSDavid du Colombier 	/* compute width of qid.path */
5939ef1f84bSDavid du Colombier 	w = 0;
5949ef1f84bSDavid du Colombier 	for(i = 0; i <= f->maxfd; i++) {
5959ef1f84bSDavid du Colombier 		c = f->fd[i];
5969ef1f84bSDavid du Colombier 		if(c == nil)
5979ef1f84bSDavid du Colombier 			continue;
5989ef1f84bSDavid du Colombier 		ww = procqidwidth(c);
5999ef1f84bSDavid du Colombier 		if(ww > w)
6009ef1f84bSDavid du Colombier 			w = ww;
6019ef1f84bSDavid du Colombier 	}
6029ef1f84bSDavid du Colombier 	for(i = 0; i <= f->maxfd; i++) {
6039ef1f84bSDavid du Colombier 		c = f->fd[i];
6049ef1f84bSDavid du Colombier 		if(c == nil)
6059ef1f84bSDavid du Colombier 			continue;
6069ef1f84bSDavid du Colombier 		n += procfdprint(c, i, w, a+n, count-n);
6079ef1f84bSDavid du Colombier 		offset = procoffset(offset, a, &n);
6089ef1f84bSDavid du Colombier 	}
6099ef1f84bSDavid du Colombier 	poperror();
6109ef1f84bSDavid du Colombier 	unlock(f);
6119ef1f84bSDavid du Colombier 	qunlock(&p->debug);
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	/* copy result to user space, now that locks are released */
6149ef1f84bSDavid du Colombier 	memmove(va, buf, n);
6159ef1f84bSDavid du Colombier 
6169ef1f84bSDavid du Colombier 	return n;
6179ef1f84bSDavid du Colombier }
6189ef1f84bSDavid du Colombier 
6199ef1f84bSDavid du Colombier static void
procclose(Chan * c)6209ef1f84bSDavid du Colombier procclose(Chan * c)
6219ef1f84bSDavid du Colombier {
6229ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qtrace){
6239ef1f84bSDavid du Colombier 		lock(&tlock);
6249ef1f84bSDavid du Colombier 		if(topens > 0)
6259ef1f84bSDavid du Colombier 			topens--;
6269ef1f84bSDavid du Colombier 		if(topens == 0)
6279ef1f84bSDavid du Colombier 			proctrace = nil;
6289ef1f84bSDavid du Colombier 		unlock(&tlock);
6299ef1f84bSDavid du Colombier 	}
6309ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qns && c->aux != 0)
6319ef1f84bSDavid du Colombier 		free(c->aux);
6329ef1f84bSDavid du Colombier }
6339ef1f84bSDavid du Colombier 
6349ef1f84bSDavid du Colombier static void
int2flag(int flag,char * s)6359ef1f84bSDavid du Colombier int2flag(int flag, char *s)
6369ef1f84bSDavid du Colombier {
6379ef1f84bSDavid du Colombier 	if(flag == 0){
6389ef1f84bSDavid du Colombier 		*s = '\0';
6399ef1f84bSDavid du Colombier 		return;
6409ef1f84bSDavid du Colombier 	}
6419ef1f84bSDavid du Colombier 	*s++ = '-';
6429ef1f84bSDavid du Colombier 	if(flag & MAFTER)
6439ef1f84bSDavid du Colombier 		*s++ = 'a';
6449ef1f84bSDavid du Colombier 	if(flag & MBEFORE)
6459ef1f84bSDavid du Colombier 		*s++ = 'b';
6469ef1f84bSDavid du Colombier 	if(flag & MCREATE)
6479ef1f84bSDavid du Colombier 		*s++ = 'c';
6489ef1f84bSDavid du Colombier 	if(flag & MCACHE)
6499ef1f84bSDavid du Colombier 		*s++ = 'C';
6509ef1f84bSDavid du Colombier 	*s = '\0';
6519ef1f84bSDavid du Colombier }
6529ef1f84bSDavid du Colombier 
6539ef1f84bSDavid du Colombier static int
procargs(Proc * p,char * buf,int nbuf)6549ef1f84bSDavid du Colombier procargs(Proc *p, char *buf, int nbuf)
6559ef1f84bSDavid du Colombier {
6569ef1f84bSDavid du Colombier 	int j, k, m;
6579ef1f84bSDavid du Colombier 	char *a;
6589ef1f84bSDavid du Colombier 	int n;
6599ef1f84bSDavid du Colombier 
6609ef1f84bSDavid du Colombier 	a = p->args;
6619ef1f84bSDavid du Colombier 	if(p->setargs){
6629ef1f84bSDavid du Colombier 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
6639ef1f84bSDavid du Colombier 		return strlen(buf);
6649ef1f84bSDavid du Colombier 	}
6659ef1f84bSDavid du Colombier 	n = p->nargs;
6669ef1f84bSDavid du Colombier 	for(j = 0; j < nbuf - 1; j += m){
6679ef1f84bSDavid du Colombier 		if(n <= 0)
6689ef1f84bSDavid du Colombier 			break;
6699ef1f84bSDavid du Colombier 		if(j != 0)
6709ef1f84bSDavid du Colombier 			buf[j++] = ' ';
6719ef1f84bSDavid du Colombier 		m = snprint(buf+j, nbuf-j, "%q",  a);
6729ef1f84bSDavid du Colombier 		k = strlen(a) + 1;
6739ef1f84bSDavid du Colombier 		a += k;
6749ef1f84bSDavid du Colombier 		n -= k;
6759ef1f84bSDavid du Colombier 	}
6769ef1f84bSDavid du Colombier 	return j;
6779ef1f84bSDavid du Colombier }
6789ef1f84bSDavid du Colombier 
6799ef1f84bSDavid du Colombier static int
eventsavailable(void *)6809ef1f84bSDavid du Colombier eventsavailable(void *)
6819ef1f84bSDavid du Colombier {
6829ef1f84bSDavid du Colombier 	return tproduced > tconsumed;
6839ef1f84bSDavid du Colombier }
6849ef1f84bSDavid du Colombier 
6859ef1f84bSDavid du Colombier static long
procread(Chan * c,void * va,long n,vlong off)6869ef1f84bSDavid du Colombier procread(Chan *c, void *va, long n, vlong off)
6879ef1f84bSDavid du Colombier {
6889ef1f84bSDavid du Colombier 	Proc *p;
6899ef1f84bSDavid du Colombier 	long l, r;
6909ef1f84bSDavid du Colombier 	Waitq *wq;
6919ef1f84bSDavid du Colombier 	Ureg kur;
6929ef1f84bSDavid du Colombier 	uchar *rptr;
6939ef1f84bSDavid du Colombier 	Asm *asm;
6949ef1f84bSDavid du Colombier 	Mntwalk *mw;
6959ef1f84bSDavid du Colombier 	Segment *sg, *s;
6969ef1f84bSDavid du Colombier 	int i, j, navail, ne, pid, rsize;
6979ef1f84bSDavid du Colombier 	char flag[10], *sps, *srv, statbuf[NSEG*64];
6989ef1f84bSDavid du Colombier 	uintptr offset, klimit;
6999ef1f84bSDavid du Colombier 	uvlong u;
7009ef1f84bSDavid du Colombier 
7019ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
7029ef1f84bSDavid du Colombier 		return devdirread(c, va, n, 0, 0, procgen);
7039ef1f84bSDavid du Colombier 
7049ef1f84bSDavid du Colombier 	offset = off;
7059ef1f84bSDavid du Colombier 
7069ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qtrace){
7079ef1f84bSDavid du Colombier 		if(!eventsavailable(nil))
7089ef1f84bSDavid du Colombier 			return 0;
7099ef1f84bSDavid du Colombier 
7109ef1f84bSDavid du Colombier 		rptr = va;
7119ef1f84bSDavid du Colombier 		navail = tproduced - tconsumed;
7129ef1f84bSDavid du Colombier 		if(navail > n / sizeof(Traceevent))
7139ef1f84bSDavid du Colombier 			navail = n / sizeof(Traceevent);
7149ef1f84bSDavid du Colombier 		while(navail > 0) {
7159ef1f84bSDavid du Colombier 			if((tconsumed & Emask) + navail > Nevents)
7169ef1f84bSDavid du Colombier 				ne = Nevents - (tconsumed & Emask);
7179ef1f84bSDavid du Colombier 			else
7189ef1f84bSDavid du Colombier 				ne = navail;
7199ef1f84bSDavid du Colombier 			i = ne * sizeof(Traceevent);
7209ef1f84bSDavid du Colombier 			memmove(rptr, &tevents[tconsumed & Emask], i);
7219ef1f84bSDavid du Colombier 
7229ef1f84bSDavid du Colombier 			tconsumed += ne;
7239ef1f84bSDavid du Colombier 			rptr += i;
7249ef1f84bSDavid du Colombier 			navail -= ne;
7259ef1f84bSDavid du Colombier 		}
7269ef1f84bSDavid du Colombier 		return rptr - (uchar*)va;
7279ef1f84bSDavid du Colombier 	}
7289ef1f84bSDavid du Colombier 
7299ef1f84bSDavid du Colombier 	if((p = psincref(SLOT(c->qid))) == nil)
7309ef1f84bSDavid du Colombier 		error(Eprocdied);
7319ef1f84bSDavid du Colombier 	if(p->pid != PID(c->qid)){
7329ef1f84bSDavid du Colombier 		psdecref(p);
7339ef1f84bSDavid du Colombier 		error(Eprocdied);
7349ef1f84bSDavid du Colombier 	}
7359ef1f84bSDavid du Colombier 
7369ef1f84bSDavid du Colombier 	switch(QID(c->qid)){
7379ef1f84bSDavid du Colombier 	default:
7389ef1f84bSDavid du Colombier 		psdecref(p);
7399ef1f84bSDavid du Colombier 		break;
7409ef1f84bSDavid du Colombier 	case Qargs:
7419ef1f84bSDavid du Colombier 		qlock(&p->debug);
7429ef1f84bSDavid du Colombier 		j = procargs(p, up->genbuf, sizeof up->genbuf);
7439ef1f84bSDavid du Colombier 		qunlock(&p->debug);
7449ef1f84bSDavid du Colombier 		psdecref(p);
7459ef1f84bSDavid du Colombier 		if(offset >= j)
7469ef1f84bSDavid du Colombier 			return 0;
7479ef1f84bSDavid du Colombier 		if(offset+n > j)
7489ef1f84bSDavid du Colombier 			n = j-offset;
7499ef1f84bSDavid du Colombier 		memmove(va, &up->genbuf[offset], n);
7509ef1f84bSDavid du Colombier 		return n;
7519ef1f84bSDavid du Colombier 
7529ef1f84bSDavid du Colombier 	case Qsyscall:
7539ef1f84bSDavid du Colombier 		if(p->syscalltrace == nil)
7549ef1f84bSDavid du Colombier 			return 0;
7559ef1f84bSDavid du Colombier 		return readstr(offset, va, n, p->syscalltrace);
7569ef1f84bSDavid du Colombier 
7579ef1f84bSDavid du Colombier 	case Qmem:
758fe56f827SDavid du Colombier 		if(!iskaddr(offset)
7599ef1f84bSDavid du Colombier 		|| (offset >= USTKTOP-USTKSIZE && offset < USTKTOP)){
7609ef1f84bSDavid du Colombier 			r = procctlmemio(p, offset, n, va, 1);
7619ef1f84bSDavid du Colombier 			psdecref(p);
7629ef1f84bSDavid du Colombier 			return r;
7639ef1f84bSDavid du Colombier 		}
7649ef1f84bSDavid du Colombier 
7659ef1f84bSDavid du Colombier 		if(!iseve()){
7669ef1f84bSDavid du Colombier 			psdecref(p);
7679ef1f84bSDavid du Colombier 			error(Eperm);
7689ef1f84bSDavid du Colombier 		}
7699ef1f84bSDavid du Colombier 
7709ef1f84bSDavid du Colombier 		/* validate kernel addresses */
7719ef1f84bSDavid du Colombier 		if(offset < PTR2UINT(end)) {
7729ef1f84bSDavid du Colombier 			if(offset+n > PTR2UINT(end))
7739ef1f84bSDavid du Colombier 				n = PTR2UINT(end) - offset;
7749ef1f84bSDavid du Colombier 			memmove(va, UINT2PTR(offset), n);
7759ef1f84bSDavid du Colombier 			psdecref(p);
7769ef1f84bSDavid du Colombier 			return n;
7779ef1f84bSDavid du Colombier 		}
7789ef1f84bSDavid du Colombier 		for(asm = asmlist; asm != nil; asm = asm->next){
7799ef1f84bSDavid du Colombier 			if(asm->kbase == 0)
7809ef1f84bSDavid du Colombier 				continue;
7819ef1f84bSDavid du Colombier 			klimit = asm->kbase + (asm->limit - asm->base);
7829ef1f84bSDavid du Colombier 
7839ef1f84bSDavid du Colombier 			/* klimit-1 because klimit might be zero!; hmmm not now but... */
7849ef1f84bSDavid du Colombier 			if(asm->kbase <= offset && offset <= klimit-1){
7859ef1f84bSDavid du Colombier 				if(offset+n >= klimit-1)
7869ef1f84bSDavid du Colombier 					n = klimit - offset;
7879ef1f84bSDavid du Colombier 				memmove(va, UINT2PTR(offset), n);
7889ef1f84bSDavid du Colombier 				psdecref(p);
7899ef1f84bSDavid du Colombier 				return n;
7909ef1f84bSDavid du Colombier 			}
7919ef1f84bSDavid du Colombier 		}
7929ef1f84bSDavid du Colombier 		psdecref(p);
7939ef1f84bSDavid du Colombier 		error(Ebadarg);
7949ef1f84bSDavid du Colombier 
7959ef1f84bSDavid du Colombier 	case Qprofile:
7969ef1f84bSDavid du Colombier 		s = p->seg[TSEG];
7979ef1f84bSDavid du Colombier 		if(s == 0 || s->profile == 0)
7989ef1f84bSDavid du Colombier 			error("profile is off");
7999ef1f84bSDavid du Colombier 		i = (s->top-s->base)>>LRESPROF;
8009ef1f84bSDavid du Colombier 		i *= sizeof(*s->profile);
8019ef1f84bSDavid du Colombier 		if(offset >= i){
8029ef1f84bSDavid du Colombier 			psdecref(p);
8039ef1f84bSDavid du Colombier 			return 0;
8049ef1f84bSDavid du Colombier 		}
8059ef1f84bSDavid du Colombier 		if(offset+n > i)
8069ef1f84bSDavid du Colombier 			n = i - offset;
8079ef1f84bSDavid du Colombier 		memmove(va, ((char*)s->profile)+offset, n);
8089ef1f84bSDavid du Colombier 		psdecref(p);
8099ef1f84bSDavid du Colombier 		return n;
8109ef1f84bSDavid du Colombier 
8119ef1f84bSDavid du Colombier 	case Qnote:
8129ef1f84bSDavid du Colombier 		qlock(&p->debug);
8139ef1f84bSDavid du Colombier 		if(waserror()){
8149ef1f84bSDavid du Colombier 			qunlock(&p->debug);
8159ef1f84bSDavid du Colombier 			psdecref(p);
8169ef1f84bSDavid du Colombier 			nexterror();
8179ef1f84bSDavid du Colombier 		}
8189ef1f84bSDavid du Colombier 		if(p->pid != PID(c->qid))
8199ef1f84bSDavid du Colombier 			error(Eprocdied);
8209ef1f84bSDavid du Colombier 		if(n < 1)	/* must accept at least the '\0' */
8219ef1f84bSDavid du Colombier 			error(Etoosmall);
8229ef1f84bSDavid du Colombier 		if(p->nnote == 0)
8239ef1f84bSDavid du Colombier 			n = 0;
8249ef1f84bSDavid du Colombier 		else {
8259ef1f84bSDavid du Colombier 			i = strlen(p->note[0].msg) + 1;
8269ef1f84bSDavid du Colombier 			if(i > n)
8279ef1f84bSDavid du Colombier 				i = n;
8289ef1f84bSDavid du Colombier 			rptr = va;
8299ef1f84bSDavid du Colombier 			memmove(rptr, p->note[0].msg, i);
8309ef1f84bSDavid du Colombier 			rptr[i-1] = '\0';
8319ef1f84bSDavid du Colombier 			p->nnote--;
8329ef1f84bSDavid du Colombier 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
8339ef1f84bSDavid du Colombier 			n = i;
8349ef1f84bSDavid du Colombier 		}
8359ef1f84bSDavid du Colombier 		if(p->nnote == 0)
8369ef1f84bSDavid du Colombier 			p->notepending = 0;
8379ef1f84bSDavid du Colombier 		poperror();
8389ef1f84bSDavid du Colombier 		qunlock(&p->debug);
8399ef1f84bSDavid du Colombier 		psdecref(p);
8409ef1f84bSDavid du Colombier 		return n;
8419ef1f84bSDavid du Colombier 
8429ef1f84bSDavid du Colombier 	case Qproc:
8439ef1f84bSDavid du Colombier 		if(offset >= sizeof(Proc)){
8449ef1f84bSDavid du Colombier 			psdecref(p);
8459ef1f84bSDavid du Colombier 			return 0;
8469ef1f84bSDavid du Colombier 		}
8479ef1f84bSDavid du Colombier 		if(offset+n > sizeof(Proc))
8489ef1f84bSDavid du Colombier 			n = sizeof(Proc) - offset;
8499ef1f84bSDavid du Colombier 		memmove(va, ((char*)p)+offset, n);
8509ef1f84bSDavid du Colombier 		psdecref(p);
8519ef1f84bSDavid du Colombier 		return n;
8529ef1f84bSDavid du Colombier 
8539ef1f84bSDavid du Colombier 	case Qregs:
8549ef1f84bSDavid du Colombier 		rptr = (uchar*)p->dbgreg;
8559ef1f84bSDavid du Colombier 		rsize = sizeof(Ureg);
8569ef1f84bSDavid du Colombier 	regread:
8579ef1f84bSDavid du Colombier 		if(rptr == 0){
8589ef1f84bSDavid du Colombier 			psdecref(p);
8599ef1f84bSDavid du Colombier 			error(Enoreg);
8609ef1f84bSDavid du Colombier 		}
8619ef1f84bSDavid du Colombier 		if(offset >= rsize){
8629ef1f84bSDavid du Colombier 			psdecref(p);
8639ef1f84bSDavid du Colombier 			return 0;
8649ef1f84bSDavid du Colombier 		}
8659ef1f84bSDavid du Colombier 		if(offset+n > rsize)
8669ef1f84bSDavid du Colombier 			n = rsize - offset;
8679ef1f84bSDavid du Colombier 		memmove(va, rptr+offset, n);
8689ef1f84bSDavid du Colombier 		psdecref(p);
8699ef1f84bSDavid du Colombier 		return n;
8709ef1f84bSDavid du Colombier 
8719ef1f84bSDavid du Colombier 	case Qkregs:
8729ef1f84bSDavid du Colombier 		memset(&kur, 0, sizeof(Ureg));
8739ef1f84bSDavid du Colombier 		setkernur(&kur, p);
8749ef1f84bSDavid du Colombier 		rptr = (uchar*)&kur;
8759ef1f84bSDavid du Colombier 		rsize = sizeof(Ureg);
8769ef1f84bSDavid du Colombier 		goto regread;
8779ef1f84bSDavid du Colombier 
8789ef1f84bSDavid du Colombier 	case Qfpregs:
8799ef1f84bSDavid du Colombier 		r = fpudevprocio(p, va, n, offset, 0);
8809ef1f84bSDavid du Colombier 		psdecref(p);
8819ef1f84bSDavid du Colombier 		return r;
8829ef1f84bSDavid du Colombier 
8839ef1f84bSDavid du Colombier 	case Qstatus:
8849ef1f84bSDavid du Colombier 		if(offset >= STATSIZE){
8859ef1f84bSDavid du Colombier 			psdecref(p);
8869ef1f84bSDavid du Colombier 			return 0;
8879ef1f84bSDavid du Colombier 		}
8889ef1f84bSDavid du Colombier 		if(offset+n > STATSIZE)
8899ef1f84bSDavid du Colombier 			n = STATSIZE - offset;
8909ef1f84bSDavid du Colombier 
8919ef1f84bSDavid du Colombier 		sps = p->psstate;
8929ef1f84bSDavid du Colombier 		if(sps == 0)
8939ef1f84bSDavid du Colombier 			sps = statename[p->state];
8949ef1f84bSDavid du Colombier 		memset(statbuf, ' ', sizeof statbuf);
8959ef1f84bSDavid du Colombier 		sprint(statbuf, "%-*.*s%-*.*s%-12.11s",
8969ef1f84bSDavid du Colombier 			KNAMELEN, KNAMELEN-1, p->text,
8979ef1f84bSDavid du Colombier 			KNAMELEN, KNAMELEN-1, p->user,
8989ef1f84bSDavid du Colombier 			sps);
8999ef1f84bSDavid du Colombier 		j = 2*KNAMELEN + 12;
9009ef1f84bSDavid du Colombier 
9019ef1f84bSDavid du Colombier 		for(i = 0; i < 6; i++) {
9029ef1f84bSDavid du Colombier 			l = p->time[i];
9039ef1f84bSDavid du Colombier 			if(i == TReal)
9049ef1f84bSDavid du Colombier 				l = sys->ticks - l;
9059ef1f84bSDavid du Colombier 			l = TK2MS(l);
9069ef1f84bSDavid du Colombier 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
9079ef1f84bSDavid du Colombier 		}
9089ef1f84bSDavid du Colombier 		/* ignore stack, which is mostly non-existent */
9099ef1f84bSDavid du Colombier 		u = 0;
9109ef1f84bSDavid du Colombier 		for(i=1; i<NSEG; i++){
9119ef1f84bSDavid du Colombier 			s = p->seg[i];
9129ef1f84bSDavid du Colombier 			if(s)
9139ef1f84bSDavid du Colombier 				u += s->top - s->base;
9149ef1f84bSDavid du Colombier 		}
9159ef1f84bSDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, u>>10, NUMSIZE);
9169ef1f84bSDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
9179ef1f84bSDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
9189ef1f84bSDavid du Colombier 		memmove(va, statbuf+offset, n);
9199ef1f84bSDavid du Colombier 		psdecref(p);
9209ef1f84bSDavid du Colombier 		return n;
9219ef1f84bSDavid du Colombier 
9229ef1f84bSDavid du Colombier 	case Qsegment:
9239ef1f84bSDavid du Colombier 		j = 0;
9249ef1f84bSDavid du Colombier 		for(i = 0; i < NSEG; i++) {
9259ef1f84bSDavid du Colombier 			sg = p->seg[i];
9269ef1f84bSDavid du Colombier 			if(sg == 0)
9279ef1f84bSDavid du Colombier 				continue;
928406c76faSDavid du Colombier 			j += snprint(statbuf+j, sizeof statbuf - j,
929406c76faSDavid du Colombier 				"%-6s %c%c %p %p %4d\n",
9309ef1f84bSDavid du Colombier 				sname[sg->type&SG_TYPE],
9319ef1f84bSDavid du Colombier 				sg->type&SG_RONLY ? 'R' : ' ',
9329ef1f84bSDavid du Colombier 				sg->profile ? 'P' : ' ',
9339ef1f84bSDavid du Colombier 				sg->base, sg->top, sg->ref);
9349ef1f84bSDavid du Colombier 		}
9359ef1f84bSDavid du Colombier 		psdecref(p);
9369ef1f84bSDavid du Colombier 		if(offset >= j)
9379ef1f84bSDavid du Colombier 			return 0;
9389ef1f84bSDavid du Colombier 		if(offset+n > j)
9399ef1f84bSDavid du Colombier 			n = j-offset;
9409ef1f84bSDavid du Colombier 		if(n == 0 && offset == 0)
9419ef1f84bSDavid du Colombier 			exhausted("segments");
9429ef1f84bSDavid du Colombier 		memmove(va, &statbuf[offset], n);
9439ef1f84bSDavid du Colombier 		return n;
9449ef1f84bSDavid du Colombier 
9459ef1f84bSDavid du Colombier 	case Qwait:
9469ef1f84bSDavid du Colombier 		if(!canqlock(&p->qwaitr)){
9479ef1f84bSDavid du Colombier 			psdecref(p);
9489ef1f84bSDavid du Colombier 			error(Einuse);
9499ef1f84bSDavid du Colombier 		}
9509ef1f84bSDavid du Colombier 
9519ef1f84bSDavid du Colombier 		if(waserror()) {
9529ef1f84bSDavid du Colombier 			qunlock(&p->qwaitr);
9539ef1f84bSDavid du Colombier 			psdecref(p);
9549ef1f84bSDavid du Colombier 			nexterror();
9559ef1f84bSDavid du Colombier 		}
9569ef1f84bSDavid du Colombier 
9579ef1f84bSDavid du Colombier 		lock(&p->exl);
9589ef1f84bSDavid du Colombier 		if(up == p && p->nchild == 0 && p->waitq == 0) {
9599ef1f84bSDavid du Colombier 			unlock(&p->exl);
9609ef1f84bSDavid du Colombier 			error(Enochild);
9619ef1f84bSDavid du Colombier 		}
9629ef1f84bSDavid du Colombier 		pid = p->pid;
9639ef1f84bSDavid du Colombier 		while(p->waitq == 0) {
9649ef1f84bSDavid du Colombier 			unlock(&p->exl);
9659ef1f84bSDavid du Colombier 			sleep(&p->waitr, haswaitq, p);
9669ef1f84bSDavid du Colombier 			if(p->pid != pid)
9679ef1f84bSDavid du Colombier 				error(Eprocdied);
9689ef1f84bSDavid du Colombier 			lock(&p->exl);
9699ef1f84bSDavid du Colombier 		}
9709ef1f84bSDavid du Colombier 		wq = p->waitq;
9719ef1f84bSDavid du Colombier 		p->waitq = wq->next;
9729ef1f84bSDavid du Colombier 		p->nwait--;
9739ef1f84bSDavid du Colombier 		unlock(&p->exl);
9749ef1f84bSDavid du Colombier 
9759ef1f84bSDavid du Colombier 		poperror();
9769ef1f84bSDavid du Colombier 		qunlock(&p->qwaitr);
9779ef1f84bSDavid du Colombier 		psdecref(p);
9789ef1f84bSDavid du Colombier 		n = snprint(va, n, "%d %lud %lud %lud %q",
9799ef1f84bSDavid du Colombier 			wq->w.pid,
9809ef1f84bSDavid du Colombier 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
9819ef1f84bSDavid du Colombier 			wq->w.msg);
9829ef1f84bSDavid du Colombier 		free(wq);
9839ef1f84bSDavid du Colombier 		return n;
9849ef1f84bSDavid du Colombier 
9859ef1f84bSDavid du Colombier 	case Qns:
9869ef1f84bSDavid du Colombier 		qlock(&p->debug);
9879ef1f84bSDavid du Colombier 		if(waserror()){
9889ef1f84bSDavid du Colombier 			qunlock(&p->debug);
9899ef1f84bSDavid du Colombier 			psdecref(p);
9909ef1f84bSDavid du Colombier 			nexterror();
9919ef1f84bSDavid du Colombier 		}
9929ef1f84bSDavid du Colombier 		if(p->pgrp == nil || p->pid != PID(c->qid))
9939ef1f84bSDavid du Colombier 			error(Eprocdied);
9949ef1f84bSDavid du Colombier 		mw = c->aux;
995406c76faSDavid du Colombier 		if(mw == nil)
996406c76faSDavid du Colombier 			error(Enomem);
9979ef1f84bSDavid du Colombier 		if(mw->cddone){
9989ef1f84bSDavid du Colombier 			poperror();
9999ef1f84bSDavid du Colombier 			qunlock(&p->debug);
10009ef1f84bSDavid du Colombier 			psdecref(p);
10019ef1f84bSDavid du Colombier 			return 0;
10029ef1f84bSDavid du Colombier 		}
10039ef1f84bSDavid du Colombier 		mntscan(mw, p);
10049ef1f84bSDavid du Colombier 		if(mw->mh == 0){
10059ef1f84bSDavid du Colombier 			mw->cddone = 1;
10069ef1f84bSDavid du Colombier 			i = snprint(va, n, "cd %s\n", p->dot->path->s);
10079ef1f84bSDavid du Colombier 			poperror();
10089ef1f84bSDavid du Colombier 			qunlock(&p->debug);
10099ef1f84bSDavid du Colombier 			psdecref(p);
10109ef1f84bSDavid du Colombier 			return i;
10119ef1f84bSDavid du Colombier 		}
10129ef1f84bSDavid du Colombier 		int2flag(mw->cm->mflag, flag);
10139ef1f84bSDavid du Colombier 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
10149ef1f84bSDavid du Colombier 			srv = srvname(mw->cm->to->mchan);
10159ef1f84bSDavid du Colombier 			i = snprint(va, n, "mount %s %s %s %s\n", flag,
10169ef1f84bSDavid du Colombier 				srv==nil? mw->cm->to->mchan->path->s : srv,
10179ef1f84bSDavid du Colombier 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
10189ef1f84bSDavid du Colombier 			free(srv);
10199ef1f84bSDavid du Colombier 		}else
10209ef1f84bSDavid du Colombier 			i = snprint(va, n, "bind %s %s %s\n", flag,
10219ef1f84bSDavid du Colombier 				mw->cm->to->path->s, mw->mh->from->path->s);
10229ef1f84bSDavid du Colombier 		poperror();
10239ef1f84bSDavid du Colombier 		qunlock(&p->debug);
10249ef1f84bSDavid du Colombier 		psdecref(p);
10259ef1f84bSDavid du Colombier 		return i;
10269ef1f84bSDavid du Colombier 
10279ef1f84bSDavid du Colombier 	case Qnoteid:
10289ef1f84bSDavid du Colombier 		r = readnum(offset, va, n, p->noteid, NUMSIZE);
10299ef1f84bSDavid du Colombier 		psdecref(p);
10309ef1f84bSDavid du Colombier 		return r;
10319ef1f84bSDavid du Colombier 	case Qfd:
10329ef1f84bSDavid du Colombier 		r = procfds(p, va, n, offset);
10339ef1f84bSDavid du Colombier 		psdecref(p);
10349ef1f84bSDavid du Colombier 		return r;
10359ef1f84bSDavid du Colombier 	}
10369ef1f84bSDavid du Colombier 	error(Egreg);
10379ef1f84bSDavid du Colombier 	return 0;			/* not reached */
10389ef1f84bSDavid du Colombier }
10399ef1f84bSDavid du Colombier 
10409ef1f84bSDavid du Colombier static void
mntscan(Mntwalk * mw,Proc * p)10419ef1f84bSDavid du Colombier mntscan(Mntwalk *mw, Proc *p)
10429ef1f84bSDavid du Colombier {
10439ef1f84bSDavid du Colombier 	Pgrp *pg;
10449ef1f84bSDavid du Colombier 	Mount *t;
10459ef1f84bSDavid du Colombier 	Mhead *f;
10469ef1f84bSDavid du Colombier 	int best, i, last, nxt;
10479ef1f84bSDavid du Colombier 
10489ef1f84bSDavid du Colombier 	pg = p->pgrp;
10499ef1f84bSDavid du Colombier 	rlock(&pg->ns);
10509ef1f84bSDavid du Colombier 
10519ef1f84bSDavid du Colombier 	nxt = 0;
10529ef1f84bSDavid du Colombier 	best = (int)(~0U>>1);		/* largest 2's complement int */
10539ef1f84bSDavid du Colombier 
10549ef1f84bSDavid du Colombier 	last = 0;
10559ef1f84bSDavid du Colombier 	if(mw->mh)
10569ef1f84bSDavid du Colombier 		last = mw->cm->mountid;
10579ef1f84bSDavid du Colombier 
10589ef1f84bSDavid du Colombier 	for(i = 0; i < MNTHASH; i++) {
10599ef1f84bSDavid du Colombier 		for(f = pg->mnthash[i]; f; f = f->hash) {
10609ef1f84bSDavid du Colombier 			for(t = f->mount; t; t = t->next) {
10619ef1f84bSDavid du Colombier 				if(mw->mh == 0 ||
10629ef1f84bSDavid du Colombier 				  (t->mountid > last && t->mountid < best)) {
10639ef1f84bSDavid du Colombier 					mw->cm = t;
10649ef1f84bSDavid du Colombier 					mw->mh = f;
10659ef1f84bSDavid du Colombier 					best = mw->cm->mountid;
10669ef1f84bSDavid du Colombier 					nxt = 1;
10679ef1f84bSDavid du Colombier 				}
10689ef1f84bSDavid du Colombier 			}
10699ef1f84bSDavid du Colombier 		}
10709ef1f84bSDavid du Colombier 	}
10719ef1f84bSDavid du Colombier 	if(nxt == 0)
10729ef1f84bSDavid du Colombier 		mw->mh = 0;
10739ef1f84bSDavid du Colombier 
10749ef1f84bSDavid du Colombier 	runlock(&pg->ns);
10759ef1f84bSDavid du Colombier }
10769ef1f84bSDavid du Colombier 
10779ef1f84bSDavid du Colombier static long
procwrite(Chan * c,void * va,long n,vlong off)10789ef1f84bSDavid du Colombier procwrite(Chan *c, void *va, long n, vlong off)
10799ef1f84bSDavid du Colombier {
10809ef1f84bSDavid du Colombier 	Proc *p, *t;
10819ef1f84bSDavid du Colombier 	int i, id, l;
10829ef1f84bSDavid du Colombier 	char *args, buf[ERRMAX];
10839ef1f84bSDavid du Colombier 	uintptr offset;
10849ef1f84bSDavid du Colombier 
10859ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
10869ef1f84bSDavid du Colombier 		error(Eisdir);
10879ef1f84bSDavid du Colombier 
10889ef1f84bSDavid du Colombier 	/* Use the remembered noteid in the channel rather
10899ef1f84bSDavid du Colombier 	 * than the process pgrpid
10909ef1f84bSDavid du Colombier 	 */
10919ef1f84bSDavid du Colombier 	if(QID(c->qid) == Qnotepg) {
10929ef1f84bSDavid du Colombier 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
10939ef1f84bSDavid du Colombier 		return n;
10949ef1f84bSDavid du Colombier 	}
10959ef1f84bSDavid du Colombier 
10969ef1f84bSDavid du Colombier 	if((p = psincref(SLOT(c->qid))) == nil)
10979ef1f84bSDavid du Colombier 		error(Eprocdied);
10989ef1f84bSDavid du Colombier 
10999ef1f84bSDavid du Colombier 	qlock(&p->debug);
11009ef1f84bSDavid du Colombier 	if(waserror()){
11019ef1f84bSDavid du Colombier 		qunlock(&p->debug);
11029ef1f84bSDavid du Colombier 		psdecref(p);
11039ef1f84bSDavid du Colombier 		nexterror();
11049ef1f84bSDavid du Colombier 	}
11059ef1f84bSDavid du Colombier 	if(p->pid != PID(c->qid))
11069ef1f84bSDavid du Colombier 		error(Eprocdied);
11079ef1f84bSDavid du Colombier 
11089ef1f84bSDavid du Colombier 	offset = off;
11099ef1f84bSDavid du Colombier 
11109ef1f84bSDavid du Colombier 	switch(QID(c->qid)){
11119ef1f84bSDavid du Colombier 	case Qargs:
11129ef1f84bSDavid du Colombier 		if(n == 0)
11139ef1f84bSDavid du Colombier 			error(Eshort);
11149ef1f84bSDavid du Colombier 		if(n >= ERRMAX)
11159ef1f84bSDavid du Colombier 			error(Etoobig);
11169ef1f84bSDavid du Colombier 		memmove(buf, va, n);
11179ef1f84bSDavid du Colombier 		args = malloc(n+1);
11189ef1f84bSDavid du Colombier 		if(args == nil)
11199ef1f84bSDavid du Colombier 			error(Enomem);
11209ef1f84bSDavid du Colombier 		memmove(args, buf, n);
11219ef1f84bSDavid du Colombier 		l = n;
11229ef1f84bSDavid du Colombier 		if(args[l-1] != 0)
11239ef1f84bSDavid du Colombier 			args[l++] = 0;
11249ef1f84bSDavid du Colombier 		free(p->args);
11259ef1f84bSDavid du Colombier 		p->nargs = l;
11269ef1f84bSDavid du Colombier 		p->args = args;
11279ef1f84bSDavid du Colombier 		p->setargs = 1;
11289ef1f84bSDavid du Colombier 		break;
11299ef1f84bSDavid du Colombier 
11309ef1f84bSDavid du Colombier 	case Qmem:
11319ef1f84bSDavid du Colombier 		if(p->state != Stopped)
11329ef1f84bSDavid du Colombier 			error(Ebadctl);
11339ef1f84bSDavid du Colombier 
11349ef1f84bSDavid du Colombier 		n = procctlmemio(p, offset, n, va, 0);
11359ef1f84bSDavid du Colombier 		break;
11369ef1f84bSDavid du Colombier 
11379ef1f84bSDavid du Colombier 	case Qregs:
11389ef1f84bSDavid du Colombier 		if(offset >= sizeof(Ureg))
11399ef1f84bSDavid du Colombier 			n = 0;
11409ef1f84bSDavid du Colombier 		else if(offset+n > sizeof(Ureg))
11419ef1f84bSDavid du Colombier 			n = sizeof(Ureg) - offset;
11429ef1f84bSDavid du Colombier 		if(p->dbgreg == 0)
11439ef1f84bSDavid du Colombier 			error(Enoreg);
11449ef1f84bSDavid du Colombier 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
11459ef1f84bSDavid du Colombier 		break;
11469ef1f84bSDavid du Colombier 
11479ef1f84bSDavid du Colombier 	case Qfpregs:
11489ef1f84bSDavid du Colombier 		n = fpudevprocio(p, va, n, offset, 1);
11499ef1f84bSDavid du Colombier 		break;
11509ef1f84bSDavid du Colombier 
11519ef1f84bSDavid du Colombier 	case Qctl:
11529ef1f84bSDavid du Colombier 		procctlreq(p, va, n);
11539ef1f84bSDavid du Colombier 		break;
11549ef1f84bSDavid du Colombier 
11559ef1f84bSDavid du Colombier 	case Qnote:
11569ef1f84bSDavid du Colombier 		if(p->kp)
11579ef1f84bSDavid du Colombier 			error(Eperm);
11589ef1f84bSDavid du Colombier 		if(n >= ERRMAX-1)
11599ef1f84bSDavid du Colombier 			error(Etoobig);
11609ef1f84bSDavid du Colombier 		memmove(buf, va, n);
11619ef1f84bSDavid du Colombier 		buf[n] = 0;
11629ef1f84bSDavid du Colombier 		if(!postnote(p, 0, buf, NUser))
11639ef1f84bSDavid du Colombier 			error("note not posted");
11649ef1f84bSDavid du Colombier 		break;
11659ef1f84bSDavid du Colombier 	case Qnoteid:
11669ef1f84bSDavid du Colombier 		id = atoi(va);
11679ef1f84bSDavid du Colombier 		if(id == p->pid) {
11689ef1f84bSDavid du Colombier 			p->noteid = id;
11699ef1f84bSDavid du Colombier 			break;
11709ef1f84bSDavid du Colombier 		}
11719ef1f84bSDavid du Colombier 		for(i = 0; (t = psincref(i)) != nil; i++){
11729ef1f84bSDavid du Colombier 			if(t->state == Dead || t->noteid != id){
11739ef1f84bSDavid du Colombier 				psdecref(t);
11749ef1f84bSDavid du Colombier 				continue;
11759ef1f84bSDavid du Colombier 			}
11769ef1f84bSDavid du Colombier 			if(strcmp(p->user, t->user) != 0){
11779ef1f84bSDavid du Colombier 				psdecref(t);
11789ef1f84bSDavid du Colombier 				error(Eperm);
11799ef1f84bSDavid du Colombier 			}
11809ef1f84bSDavid du Colombier 			psdecref(t);
11819ef1f84bSDavid du Colombier 			p->noteid = id;
11829ef1f84bSDavid du Colombier 			break;
11839ef1f84bSDavid du Colombier 		}
11849ef1f84bSDavid du Colombier 		if(p->noteid != id)
11859ef1f84bSDavid du Colombier 			error(Ebadarg);
11869ef1f84bSDavid du Colombier 		break;
11879ef1f84bSDavid du Colombier 	default:
11889ef1f84bSDavid du Colombier 		poperror();
11899ef1f84bSDavid du Colombier 		qunlock(&p->debug);
11909ef1f84bSDavid du Colombier 		psdecref(p);
11919ef1f84bSDavid du Colombier 		pprint("unknown qid %#llux in procwrite\n", c->qid.path);
11929ef1f84bSDavid du Colombier 		error(Egreg);
11939ef1f84bSDavid du Colombier 	}
11949ef1f84bSDavid du Colombier 	poperror();
11959ef1f84bSDavid du Colombier 	qunlock(&p->debug);
11969ef1f84bSDavid du Colombier 	psdecref(p);
11979ef1f84bSDavid du Colombier 	return n;
11989ef1f84bSDavid du Colombier }
11999ef1f84bSDavid du Colombier 
12009ef1f84bSDavid du Colombier Dev procdevtab = {
12019ef1f84bSDavid du Colombier 	'p',
12029ef1f84bSDavid du Colombier 	"proc",
12039ef1f84bSDavid du Colombier 
12049ef1f84bSDavid du Colombier 	devreset,
12059ef1f84bSDavid du Colombier 	procinit,
12069ef1f84bSDavid du Colombier 	devshutdown,
12079ef1f84bSDavid du Colombier 	procattach,
12089ef1f84bSDavid du Colombier 	procwalk,
12099ef1f84bSDavid du Colombier 	procstat,
12109ef1f84bSDavid du Colombier 	procopen,
12119ef1f84bSDavid du Colombier 	devcreate,
12129ef1f84bSDavid du Colombier 	procclose,
12139ef1f84bSDavid du Colombier 	procread,
12149ef1f84bSDavid du Colombier 	devbread,
12159ef1f84bSDavid du Colombier 	procwrite,
12169ef1f84bSDavid du Colombier 	devbwrite,
12179ef1f84bSDavid du Colombier 	devremove,
12189ef1f84bSDavid du Colombier 	procwstat,
12199ef1f84bSDavid du Colombier };
12209ef1f84bSDavid du Colombier 
12219ef1f84bSDavid du Colombier static Chan*
proctext(Chan * c,Proc * p)12229ef1f84bSDavid du Colombier proctext(Chan *c, Proc *p)
12239ef1f84bSDavid du Colombier {
12249ef1f84bSDavid du Colombier 	Chan *tc;
12259ef1f84bSDavid du Colombier 	Image *i;
12269ef1f84bSDavid du Colombier 	Segment *s;
12279ef1f84bSDavid du Colombier 
12289ef1f84bSDavid du Colombier 	s = p->seg[TSEG];
12299ef1f84bSDavid du Colombier 	if(s == 0)
12309ef1f84bSDavid du Colombier 		error(Enonexist);
12319ef1f84bSDavid du Colombier 	if(p->state==Dead)
12329ef1f84bSDavid du Colombier 		error(Eprocdied);
12339ef1f84bSDavid du Colombier 
12349ef1f84bSDavid du Colombier 	lock(s);
12359ef1f84bSDavid du Colombier 	i = s->image;
12369ef1f84bSDavid du Colombier 	if(i == 0) {
12379ef1f84bSDavid du Colombier 		unlock(s);
12389ef1f84bSDavid du Colombier 		error(Eprocdied);
12399ef1f84bSDavid du Colombier 	}
12409ef1f84bSDavid du Colombier 	unlock(s);
12419ef1f84bSDavid du Colombier 
12429ef1f84bSDavid du Colombier 	lock(i);
12439ef1f84bSDavid du Colombier 	if(waserror()) {
12449ef1f84bSDavid du Colombier 		unlock(i);
12459ef1f84bSDavid du Colombier 		nexterror();
12469ef1f84bSDavid du Colombier 	}
12479ef1f84bSDavid du Colombier 
12489ef1f84bSDavid du Colombier 	tc = i->c;
12499ef1f84bSDavid du Colombier 	if(tc == 0)
12509ef1f84bSDavid du Colombier 		error(Eprocdied);
12519ef1f84bSDavid du Colombier 
12529ef1f84bSDavid du Colombier 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
12539ef1f84bSDavid du Colombier 		cclose(tc);
12549ef1f84bSDavid du Colombier 		error(Eprocdied);
12559ef1f84bSDavid du Colombier 	}
12569ef1f84bSDavid du Colombier 
1257406c76faSDavid du Colombier 	if(p->pid != PID(c->qid)){
1258406c76faSDavid du Colombier 		cclose(tc);
12599ef1f84bSDavid du Colombier 		error(Eprocdied);
1260406c76faSDavid du Colombier 	}
12619ef1f84bSDavid du Colombier 
12629ef1f84bSDavid du Colombier 	poperror();
12639ef1f84bSDavid du Colombier 	unlock(i);
12649ef1f84bSDavid du Colombier 
12659ef1f84bSDavid du Colombier 	return tc;
12669ef1f84bSDavid du Colombier }
12679ef1f84bSDavid du Colombier 
12689ef1f84bSDavid du Colombier void
procstopwait(Proc * p,int ctl)12699ef1f84bSDavid du Colombier procstopwait(Proc *p, int ctl)
12709ef1f84bSDavid du Colombier {
12719ef1f84bSDavid du Colombier 	int pid;
12729ef1f84bSDavid du Colombier 
12739ef1f84bSDavid du Colombier 	if(p->pdbg)
12749ef1f84bSDavid du Colombier 		error(Einuse);
12759ef1f84bSDavid du Colombier 	if(procstopped(p) || p->state == Broken)
12769ef1f84bSDavid du Colombier 		return;
12779ef1f84bSDavid du Colombier 
12789ef1f84bSDavid du Colombier 	if(ctl != 0)
12799ef1f84bSDavid du Colombier 		p->procctl = ctl;
12809ef1f84bSDavid du Colombier 	p->pdbg = up;
12819ef1f84bSDavid du Colombier 	pid = p->pid;
12829ef1f84bSDavid du Colombier 	qunlock(&p->debug);
12839ef1f84bSDavid du Colombier 	up->psstate = "Stopwait";
12849ef1f84bSDavid du Colombier 	if(waserror()) {
12859ef1f84bSDavid du Colombier 		p->pdbg = 0;
12869ef1f84bSDavid du Colombier 		qlock(&p->debug);
12879ef1f84bSDavid du Colombier 		nexterror();
12889ef1f84bSDavid du Colombier 	}
12899ef1f84bSDavid du Colombier 	sleep(&up->sleep, procstopped, p);
12909ef1f84bSDavid du Colombier 	poperror();
12919ef1f84bSDavid du Colombier 	qlock(&p->debug);
12929ef1f84bSDavid du Colombier 	if(p->pid != pid)
12939ef1f84bSDavid du Colombier 		error(Eprocdied);
12949ef1f84bSDavid du Colombier }
12959ef1f84bSDavid du Colombier 
12969ef1f84bSDavid du Colombier static void
procctlcloseone(Proc * p,Fgrp * f,int fd)12979ef1f84bSDavid du Colombier procctlcloseone(Proc *p, Fgrp *f, int fd)
12989ef1f84bSDavid du Colombier {
12999ef1f84bSDavid du Colombier 	Chan *c;
13009ef1f84bSDavid du Colombier 
13019ef1f84bSDavid du Colombier 	c = f->fd[fd];
13029ef1f84bSDavid du Colombier 	if(c == nil)
13039ef1f84bSDavid du Colombier 		return;
13049ef1f84bSDavid du Colombier 	f->fd[fd] = nil;
13059ef1f84bSDavid du Colombier 	unlock(f);
13069ef1f84bSDavid du Colombier 	qunlock(&p->debug);
13079ef1f84bSDavid du Colombier 	cclose(c);
13089ef1f84bSDavid du Colombier 	qlock(&p->debug);
13099ef1f84bSDavid du Colombier 	lock(f);
13109ef1f84bSDavid du Colombier }
13119ef1f84bSDavid du Colombier 
13129ef1f84bSDavid du Colombier void
procctlclosefiles(Proc * p,int all,int fd)13139ef1f84bSDavid du Colombier procctlclosefiles(Proc *p, int all, int fd)
13149ef1f84bSDavid du Colombier {
13159ef1f84bSDavid du Colombier 	int i;
13169ef1f84bSDavid du Colombier 	Fgrp *f;
13179ef1f84bSDavid du Colombier 
13189ef1f84bSDavid du Colombier 	f = p->fgrp;
13199ef1f84bSDavid du Colombier 	if(f == nil)
13209ef1f84bSDavid du Colombier 		error(Eprocdied);
13219ef1f84bSDavid du Colombier 
13229ef1f84bSDavid du Colombier 	lock(f);
13239ef1f84bSDavid du Colombier 	f->ref++;
13249ef1f84bSDavid du Colombier 	if(all)
13259ef1f84bSDavid du Colombier 		for(i = 0; i < f->maxfd; i++)
13269ef1f84bSDavid du Colombier 			procctlcloseone(p, f, i);
13279ef1f84bSDavid du Colombier 	else
13289ef1f84bSDavid du Colombier 		procctlcloseone(p, f, fd);
13299ef1f84bSDavid du Colombier 	unlock(f);
13309ef1f84bSDavid du Colombier 	closefgrp(f);
13319ef1f84bSDavid du Colombier }
13329ef1f84bSDavid du Colombier 
13339ef1f84bSDavid du Colombier static char *
parsetime(vlong * rt,char * s)13349ef1f84bSDavid du Colombier parsetime(vlong *rt, char *s)
13359ef1f84bSDavid du Colombier {
13369ef1f84bSDavid du Colombier 	uvlong ticks;
13379ef1f84bSDavid du Colombier 	ulong l;
13389ef1f84bSDavid du Colombier 	char *e, *p;
13399ef1f84bSDavid du Colombier 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
13409ef1f84bSDavid du Colombier 
13419ef1f84bSDavid du Colombier 	if (s == nil)
13429ef1f84bSDavid du Colombier 		return("missing value");
13439ef1f84bSDavid du Colombier 	ticks=strtoul(s, &e, 10);
13449ef1f84bSDavid du Colombier 	if (*e == '.'){
13459ef1f84bSDavid du Colombier 		p = e+1;
13469ef1f84bSDavid du Colombier 		l = strtoul(p, &e, 10);
13479ef1f84bSDavid du Colombier 		if(e-p > nelem(p10))
13489ef1f84bSDavid du Colombier 			return "too many digits after decimal point";
13499ef1f84bSDavid du Colombier 		if(e-p == 0)
13509ef1f84bSDavid du Colombier 			return "ill-formed number";
13519ef1f84bSDavid du Colombier 		l *= p10[e-p-1];
13529ef1f84bSDavid du Colombier 	}else
13539ef1f84bSDavid du Colombier 		l = 0;
13549ef1f84bSDavid du Colombier 	if (*e == '\0' || strcmp(e, "s") == 0){
13559ef1f84bSDavid du Colombier 		ticks = 1000000000 * ticks + l;
13569ef1f84bSDavid du Colombier 	}else if (strcmp(e, "ms") == 0){
13579ef1f84bSDavid du Colombier 		ticks = 1000000 * ticks + l/1000;
13589ef1f84bSDavid du Colombier 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
13599ef1f84bSDavid du Colombier 		ticks = 1000 * ticks + l/1000000;
13609ef1f84bSDavid du Colombier 	}else if (strcmp(e, "ns") != 0)
13619ef1f84bSDavid du Colombier 		return "unrecognized unit";
13629ef1f84bSDavid du Colombier 	*rt = ticks;
13639ef1f84bSDavid du Colombier 	return nil;
13649ef1f84bSDavid du Colombier }
13659ef1f84bSDavid du Colombier 
13669ef1f84bSDavid du Colombier static void
procctlreq(Proc * p,char * va,int n)13679ef1f84bSDavid du Colombier procctlreq(Proc *p, char *va, int n)
13689ef1f84bSDavid du Colombier {
13699ef1f84bSDavid du Colombier 	Segment *s;
13709ef1f84bSDavid du Colombier 	int npc, pri;
13719ef1f84bSDavid du Colombier 	Cmdbuf *cb;
13729ef1f84bSDavid du Colombier 	Cmdtab *ct;
13739ef1f84bSDavid du Colombier 	vlong time;
13749ef1f84bSDavid du Colombier 	char *e;
1375d46407a3SDavid du Colombier 	void (*pt)(Proc*, int, vlong, vlong);
13769ef1f84bSDavid du Colombier 
13779ef1f84bSDavid du Colombier 	if(p->kp)	/* no ctl requests to kprocs */
13789ef1f84bSDavid du Colombier 		error(Eperm);
13799ef1f84bSDavid du Colombier 
13809ef1f84bSDavid du Colombier 	cb = parsecmd(va, n);
13819ef1f84bSDavid du Colombier 	if(waserror()){
13829ef1f84bSDavid du Colombier 		free(cb);
13839ef1f84bSDavid du Colombier 		nexterror();
13849ef1f84bSDavid du Colombier 	}
13859ef1f84bSDavid du Colombier 
13869ef1f84bSDavid du Colombier 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
13879ef1f84bSDavid du Colombier 
13889ef1f84bSDavid du Colombier 	switch(ct->index){
13899ef1f84bSDavid du Colombier 	case CMclose:
13909ef1f84bSDavid du Colombier 		procctlclosefiles(p, 0, atoi(cb->f[1]));
13919ef1f84bSDavid du Colombier 		break;
13929ef1f84bSDavid du Colombier 	case CMclosefiles:
13939ef1f84bSDavid du Colombier 		procctlclosefiles(p, 1, 0);
13949ef1f84bSDavid du Colombier 		break;
13959ef1f84bSDavid du Colombier 	case CMhang:
13969ef1f84bSDavid du Colombier 		p->hang = 1;
13979ef1f84bSDavid du Colombier 		break;
13989ef1f84bSDavid du Colombier 	case CMkill:
13999ef1f84bSDavid du Colombier 		switch(p->state) {
14009ef1f84bSDavid du Colombier 		case Broken:
14019ef1f84bSDavid du Colombier 			unbreak(p);
14029ef1f84bSDavid du Colombier 			break;
14039ef1f84bSDavid du Colombier 		case Stopped:
14049ef1f84bSDavid du Colombier 			p->procctl = Proc_exitme;
14059ef1f84bSDavid du Colombier 			postnote(p, 0, "sys: killed", NExit);
14069ef1f84bSDavid du Colombier 			ready(p);
14079ef1f84bSDavid du Colombier 			break;
14089ef1f84bSDavid du Colombier 		default:
14099ef1f84bSDavid du Colombier 			p->procctl = Proc_exitme;
14109ef1f84bSDavid du Colombier 			postnote(p, 0, "sys: killed", NExit);
14119ef1f84bSDavid du Colombier 		}
14129ef1f84bSDavid du Colombier 		break;
14139ef1f84bSDavid du Colombier 	case CMnohang:
14149ef1f84bSDavid du Colombier 		p->hang = 0;
14159ef1f84bSDavid du Colombier 		break;
14169ef1f84bSDavid du Colombier 	case CMnoswap:
14179ef1f84bSDavid du Colombier 		/*retired*/
14189ef1f84bSDavid du Colombier 		break;
14199ef1f84bSDavid du Colombier 	case CMpri:
14209ef1f84bSDavid du Colombier 		pri = atoi(cb->f[1]);
14219ef1f84bSDavid du Colombier 		if(pri > PriNormal && !iseve())
14229ef1f84bSDavid du Colombier 			error(Eperm);
14239ef1f84bSDavid du Colombier 		procpriority(p, pri, 0);
14249ef1f84bSDavid du Colombier 		break;
14259ef1f84bSDavid du Colombier 	case CMfixedpri:
14269ef1f84bSDavid du Colombier 		pri = atoi(cb->f[1]);
14279ef1f84bSDavid du Colombier 		if(pri > PriNormal && !iseve())
14289ef1f84bSDavid du Colombier 			error(Eperm);
14299ef1f84bSDavid du Colombier 		procpriority(p, pri, 1);
14309ef1f84bSDavid du Colombier 		break;
14319ef1f84bSDavid du Colombier 	case CMprivate:
14329ef1f84bSDavid du Colombier 		p->privatemem = 1;
14339ef1f84bSDavid du Colombier 		break;
14349ef1f84bSDavid du Colombier 	case CMprofile:
14359ef1f84bSDavid du Colombier 		s = p->seg[TSEG];
14369ef1f84bSDavid du Colombier 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
14379ef1f84bSDavid du Colombier 			error(Ebadctl);
14389ef1f84bSDavid du Colombier 		if(s->profile != 0)
14399ef1f84bSDavid du Colombier 			free(s->profile);
14409ef1f84bSDavid du Colombier 		npc = (s->top-s->base)>>LRESPROF;
14419ef1f84bSDavid du Colombier 		s->profile = malloc(npc*sizeof(*s->profile));
14429ef1f84bSDavid du Colombier 		if(s->profile == 0)
14439ef1f84bSDavid du Colombier 			error(Enomem);
14449ef1f84bSDavid du Colombier 		break;
14459ef1f84bSDavid du Colombier 	case CMstart:
14469ef1f84bSDavid du Colombier 		if(p->state != Stopped)
14479ef1f84bSDavid du Colombier 			error(Ebadctl);
14489ef1f84bSDavid du Colombier 		ready(p);
14499ef1f84bSDavid du Colombier 		break;
14509ef1f84bSDavid du Colombier 	case CMstartstop:
14519ef1f84bSDavid du Colombier 		if(p->state != Stopped)
14529ef1f84bSDavid du Colombier 			error(Ebadctl);
14539ef1f84bSDavid du Colombier 		p->procctl = Proc_traceme;
14549ef1f84bSDavid du Colombier 		ready(p);
14559ef1f84bSDavid du Colombier 		procstopwait(p, Proc_traceme);
14569ef1f84bSDavid du Colombier 		break;
14579ef1f84bSDavid du Colombier 	case CMstartsyscall:
14589ef1f84bSDavid du Colombier 		if(p->state != Stopped)
14599ef1f84bSDavid du Colombier 			error(Ebadctl);
14609ef1f84bSDavid du Colombier 		p->procctl = Proc_tracesyscall;
14619ef1f84bSDavid du Colombier 		ready(p);
14629ef1f84bSDavid du Colombier 		procstopwait(p, Proc_tracesyscall);
14639ef1f84bSDavid du Colombier 		break;
14649ef1f84bSDavid du Colombier 	case CMstop:
14659ef1f84bSDavid du Colombier 		procstopwait(p, Proc_stopme);
14669ef1f84bSDavid du Colombier 		break;
14679ef1f84bSDavid du Colombier 	case CMwaitstop:
14689ef1f84bSDavid du Colombier 		procstopwait(p, 0);
14699ef1f84bSDavid du Colombier 		break;
14709ef1f84bSDavid du Colombier 	case CMwired:
14719ef1f84bSDavid du Colombier 		procwired(p, atoi(cb->f[1]));
14729ef1f84bSDavid du Colombier 		break;
14739ef1f84bSDavid du Colombier 	case CMtrace:
14749ef1f84bSDavid du Colombier 		switch(cb->nf){
14759ef1f84bSDavid du Colombier 		case 1:
14769ef1f84bSDavid du Colombier 			p->trace ^= 1;
14779ef1f84bSDavid du Colombier 			break;
14789ef1f84bSDavid du Colombier 		case 2:
14799ef1f84bSDavid du Colombier 			p->trace = (atoi(cb->f[1]) != 0);
14809ef1f84bSDavid du Colombier 			break;
14819ef1f84bSDavid du Colombier 		default:
14829ef1f84bSDavid du Colombier 			error("args");
14839ef1f84bSDavid du Colombier 		}
14849ef1f84bSDavid du Colombier 		break;
14859ef1f84bSDavid du Colombier 	/* real time */
14869ef1f84bSDavid du Colombier 	case CMperiod:
14879ef1f84bSDavid du Colombier 		if(p->edf == nil)
14889ef1f84bSDavid du Colombier 			edfinit(p);
14899ef1f84bSDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
14909ef1f84bSDavid du Colombier 			error(e);
14919ef1f84bSDavid du Colombier 		edfstop(p);
14929ef1f84bSDavid du Colombier 		p->edf->T = time/1000;			/* Edf times are µs */
14939ef1f84bSDavid du Colombier 		break;
14949ef1f84bSDavid du Colombier 	case CMdeadline:
14959ef1f84bSDavid du Colombier 		if(p->edf == nil)
14969ef1f84bSDavid du Colombier 			edfinit(p);
14979ef1f84bSDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))
14989ef1f84bSDavid du Colombier 			error(e);
14999ef1f84bSDavid du Colombier 		edfstop(p);
15009ef1f84bSDavid du Colombier 		p->edf->D = time/1000;
15019ef1f84bSDavid du Colombier 		break;
15029ef1f84bSDavid du Colombier 	case CMcost:
15039ef1f84bSDavid du Colombier 		if(p->edf == nil)
15049ef1f84bSDavid du Colombier 			edfinit(p);
15059ef1f84bSDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))
15069ef1f84bSDavid du Colombier 			error(e);
15079ef1f84bSDavid du Colombier 		edfstop(p);
15089ef1f84bSDavid du Colombier 		p->edf->C = time/1000;
15099ef1f84bSDavid du Colombier 		break;
15109ef1f84bSDavid du Colombier 	case CMsporadic:
15119ef1f84bSDavid du Colombier 		if(p->edf == nil)
15129ef1f84bSDavid du Colombier 			edfinit(p);
15139ef1f84bSDavid du Colombier 		p->edf->flags |= Sporadic;
15149ef1f84bSDavid du Colombier 		break;
15159ef1f84bSDavid du Colombier 	case CMdeadlinenotes:
15169ef1f84bSDavid du Colombier 		if(p->edf == nil)
15179ef1f84bSDavid du Colombier 			edfinit(p);
15189ef1f84bSDavid du Colombier 		p->edf->flags |= Sendnotes;
15199ef1f84bSDavid du Colombier 		break;
15209ef1f84bSDavid du Colombier 	case CMadmit:
15219ef1f84bSDavid du Colombier 		if(p->edf == 0)
15229ef1f84bSDavid du Colombier 			error("edf params");
15239ef1f84bSDavid du Colombier 		if(e = edfadmit(p))
15249ef1f84bSDavid du Colombier 			error(e);
15259ef1f84bSDavid du Colombier 		break;
15269ef1f84bSDavid du Colombier 	case CMextra:
15279ef1f84bSDavid du Colombier 		if(p->edf == nil)
15289ef1f84bSDavid du Colombier 			edfinit(p);
15299ef1f84bSDavid du Colombier 		p->edf->flags |= Extratime;
15309ef1f84bSDavid du Colombier 		break;
15319ef1f84bSDavid du Colombier 	case CMexpel:
15329ef1f84bSDavid du Colombier 		if(p->edf)
15339ef1f84bSDavid du Colombier 			edfstop(p);
15349ef1f84bSDavid du Colombier 		break;
15359ef1f84bSDavid du Colombier 	case CMevent:
15369ef1f84bSDavid du Colombier 		pt = proctrace;
15379ef1f84bSDavid du Colombier 		if(up->trace && pt)
1538d46407a3SDavid du Colombier 			pt(up, SUser, 0, 0);
15399ef1f84bSDavid du Colombier 		break;
15409ef1f84bSDavid du Colombier 	}
15419ef1f84bSDavid du Colombier 
15429ef1f84bSDavid du Colombier 	poperror();
15439ef1f84bSDavid du Colombier 	free(cb);
15449ef1f84bSDavid du Colombier }
15459ef1f84bSDavid du Colombier 
15469ef1f84bSDavid du Colombier static int
procstopped(void * a)15479ef1f84bSDavid du Colombier procstopped(void *a)
15489ef1f84bSDavid du Colombier {
15499ef1f84bSDavid du Colombier 	Proc *p = a;
15509ef1f84bSDavid du Colombier 	return p->state == Stopped;
15519ef1f84bSDavid du Colombier }
15529ef1f84bSDavid du Colombier 
15539ef1f84bSDavid du Colombier static int
procctlmemio(Proc * p,uintptr offset,int n,void * va,int read)15549ef1f84bSDavid du Colombier procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
15559ef1f84bSDavid du Colombier {
15569ef1f84bSDavid du Colombier 	KMap *k;
15579ef1f84bSDavid du Colombier 	Pte *pte;
15589ef1f84bSDavid du Colombier 	Page *pg;
15599ef1f84bSDavid du Colombier 	Segment *s;
15609ef1f84bSDavid du Colombier 	uintptr soff, l, pgsize;	/* hmmmm */
15619ef1f84bSDavid du Colombier 	uchar *b;
15629ef1f84bSDavid du Colombier 
15639ef1f84bSDavid du Colombier 	for(;;) {
15649ef1f84bSDavid du Colombier 		s = seg(p, offset, 1);
15659ef1f84bSDavid du Colombier 		if(s == 0)
15669ef1f84bSDavid du Colombier 			error(Ebadarg);
15679ef1f84bSDavid du Colombier 
15689ef1f84bSDavid du Colombier 		if(offset+n >= s->top)
15699ef1f84bSDavid du Colombier 			n = s->top-offset;
15709ef1f84bSDavid du Colombier 
15719ef1f84bSDavid du Colombier 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
15729ef1f84bSDavid du Colombier 			s = txt2data(p, s);
15739ef1f84bSDavid du Colombier 
15749ef1f84bSDavid du Colombier 		s->steal++;
15759ef1f84bSDavid du Colombier 		soff = offset-s->base;
15769ef1f84bSDavid du Colombier 		if(waserror()) {
15779ef1f84bSDavid du Colombier 			s->steal--;
15789ef1f84bSDavid du Colombier 			nexterror();
15799ef1f84bSDavid du Colombier 		}
1580*094d6818SDavid du Colombier 		if(fixfault(s, offset, read, 0, s->color) == 0)
15819ef1f84bSDavid du Colombier 			break;
15829ef1f84bSDavid du Colombier 		poperror();
15839ef1f84bSDavid du Colombier 		s->steal--;
15849ef1f84bSDavid du Colombier 	}
15859ef1f84bSDavid du Colombier 	poperror();
15869ef1f84bSDavid du Colombier 	pte = s->map[soff/s->ptemapmem];
15879ef1f84bSDavid du Colombier 	if(pte == 0)
15889ef1f84bSDavid du Colombier 		panic("procctlmemio");
15899ef1f84bSDavid du Colombier 	pg = pte->pages[(soff&(s->ptemapmem-1))>>s->lg2pgsize];
15909ef1f84bSDavid du Colombier 	if(pagedout(pg))
15919ef1f84bSDavid du Colombier 		panic("procctlmemio1");
15929ef1f84bSDavid du Colombier 
159357fe3081SDavid du Colombier 	pgsize = segpgsize(s);
15949ef1f84bSDavid du Colombier 	l = pgsize - (offset&(pgsize-1));
15959ef1f84bSDavid du Colombier 	if(n > l)
15969ef1f84bSDavid du Colombier 		n = l;
15979ef1f84bSDavid du Colombier 
15989ef1f84bSDavid du Colombier 	k = kmap(pg);
15999ef1f84bSDavid du Colombier 	if(waserror()) {
16009ef1f84bSDavid du Colombier 		s->steal--;
16019ef1f84bSDavid du Colombier 		kunmap(k);
16029ef1f84bSDavid du Colombier 		nexterror();
16039ef1f84bSDavid du Colombier 	}
16049ef1f84bSDavid du Colombier 	b = (uchar*)VA(k);
16059ef1f84bSDavid du Colombier 	b += offset&(pgsize-1);
16069ef1f84bSDavid du Colombier 	if(read == 1)
16079ef1f84bSDavid du Colombier 		memmove(va, b, n);	/* This can fault */
16089ef1f84bSDavid du Colombier 	else
16099ef1f84bSDavid du Colombier 		memmove(b, va, n);
16109ef1f84bSDavid du Colombier 	poperror();
16119ef1f84bSDavid du Colombier 	kunmap(k);
16129ef1f84bSDavid du Colombier 
16139ef1f84bSDavid du Colombier 	/* Ensure the process sees text page changes */
16149ef1f84bSDavid du Colombier 	if(s->flushme)
16150d74731bSDavid du Colombier 		mmucachectl(pg, PG_TXTFLUSH);
16169ef1f84bSDavid du Colombier 
16179ef1f84bSDavid du Colombier 	s->steal--;
16189ef1f84bSDavid du Colombier 
16199ef1f84bSDavid du Colombier 	if(read == 0)
16209ef1f84bSDavid du Colombier 		p->newtlb = 1;
16219ef1f84bSDavid du Colombier 
16229ef1f84bSDavid du Colombier 	return n;
16239ef1f84bSDavid du Colombier }
16249ef1f84bSDavid du Colombier 
16259ef1f84bSDavid du Colombier static Segment*
txt2data(Proc * p,Segment * s)16269ef1f84bSDavid du Colombier txt2data(Proc *p, Segment *s)
16279ef1f84bSDavid du Colombier {
16289ef1f84bSDavid du Colombier 	int i;
16299ef1f84bSDavid du Colombier 	Segment *ps;
16309ef1f84bSDavid du Colombier 
16319ef1f84bSDavid du Colombier 	ps = newseg(SG_DATA, s->base, s->top);
16329ef1f84bSDavid du Colombier 	ps->image = s->image;
16339ef1f84bSDavid du Colombier 	incref(ps->image);
16349ef1f84bSDavid du Colombier 	ps->fstart = s->fstart;
16359ef1f84bSDavid du Colombier 	ps->flen = s->flen;
16369ef1f84bSDavid du Colombier 	ps->flushme = 1;
16379ef1f84bSDavid du Colombier 
16389ef1f84bSDavid du Colombier 	qlock(&p->seglock);
16399ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++)
16409ef1f84bSDavid du Colombier 		if(p->seg[i] == s)
16419ef1f84bSDavid du Colombier 			break;
16429ef1f84bSDavid du Colombier 	if(i == NSEG)
16439ef1f84bSDavid du Colombier 		panic("segment gone");
16449ef1f84bSDavid du Colombier 
16459ef1f84bSDavid du Colombier 	qunlock(&s->lk);
16469ef1f84bSDavid du Colombier 	putseg(s);
16479ef1f84bSDavid du Colombier 	qlock(&ps->lk);
16489ef1f84bSDavid du Colombier 	p->seg[i] = ps;
16499ef1f84bSDavid du Colombier 	qunlock(&p->seglock);
16509ef1f84bSDavid du Colombier 
16519ef1f84bSDavid du Colombier 	return ps;
16529ef1f84bSDavid du Colombier }
16539ef1f84bSDavid du Colombier 
16549ef1f84bSDavid du Colombier Segment*
data2txt(Segment * s)16559ef1f84bSDavid du Colombier data2txt(Segment *s)
16569ef1f84bSDavid du Colombier {
16579ef1f84bSDavid du Colombier 	Segment *ps;
16589ef1f84bSDavid du Colombier 
16599ef1f84bSDavid du Colombier 	ps = newseg(SG_TEXT, s->base, s->top);
16609ef1f84bSDavid du Colombier 	ps->image = s->image;
16619ef1f84bSDavid du Colombier 	incref(ps->image);
16629ef1f84bSDavid du Colombier 	ps->fstart = s->fstart;
16639ef1f84bSDavid du Colombier 	ps->flen = s->flen;
16649ef1f84bSDavid du Colombier 	ps->flushme = 1;
16659ef1f84bSDavid du Colombier 
16669ef1f84bSDavid du Colombier 	return ps;
16679ef1f84bSDavid du Colombier }
1668