xref: /plan9/sys/src/9/port/devproc.c (revision 4e3613ab15c331a9ada113286cc0f2a35bc0373d)
13e12c5d1SDavid du Colombier #include	"u.h"
2e288d156SDavid du Colombier #include	<trace.h>
3e288d156SDavid du Colombier #include	"tos.h"
43e12c5d1SDavid du Colombier #include	"../port/lib.h"
53e12c5d1SDavid du Colombier #include	"mem.h"
63e12c5d1SDavid du Colombier #include	"dat.h"
73e12c5d1SDavid du Colombier #include	"fns.h"
83e12c5d1SDavid du Colombier #include	"../port/error.h"
93e12c5d1SDavid du Colombier #include	"ureg.h"
10696c1e60SDavid du Colombier #include	"../port/edf.h"
113e12c5d1SDavid du Colombier 
127dd7cddfSDavid du Colombier enum
137dd7cddfSDavid du Colombier {
147dd7cddfSDavid du Colombier 	Qdir,
15e288d156SDavid du Colombier 	Qtrace,
169a747e4fSDavid du Colombier 	Qargs,
179a747e4fSDavid du Colombier 	Qctl,
187dd7cddfSDavid du Colombier 	Qfd,
197dd7cddfSDavid du Colombier 	Qfpregs,
207dd7cddfSDavid du Colombier 	Qkregs,
213e12c5d1SDavid du Colombier 	Qmem,
223e12c5d1SDavid du Colombier 	Qnote,
23219b2ee8SDavid du Colombier 	Qnoteid,
243e12c5d1SDavid du Colombier 	Qnotepg,
257dd7cddfSDavid du Colombier 	Qns,
263e12c5d1SDavid du Colombier 	Qproc,
277dd7cddfSDavid du Colombier 	Qregs,
283e12c5d1SDavid du Colombier 	Qsegment,
293e12c5d1SDavid du Colombier 	Qstatus,
303e12c5d1SDavid du Colombier 	Qtext,
31219b2ee8SDavid du Colombier 	Qwait,
327dd7cddfSDavid du Colombier 	Qprofile,
33d1be6b08SDavid du Colombier 	Qsyscall,
343e12c5d1SDavid du Colombier };
353e12c5d1SDavid du Colombier 
369a747e4fSDavid du Colombier enum
379a747e4fSDavid du Colombier {
389a747e4fSDavid du Colombier 	CMclose,
399a747e4fSDavid du Colombier 	CMclosefiles,
409a747e4fSDavid du Colombier 	CMfixedpri,
419a747e4fSDavid du Colombier 	CMhang,
429a747e4fSDavid du Colombier 	CMkill,
439a747e4fSDavid du Colombier 	CMnohang,
44b7b24591SDavid du Colombier 	CMnoswap,
459a747e4fSDavid du Colombier 	CMpri,
469a747e4fSDavid du Colombier 	CMprivate,
479a747e4fSDavid du Colombier 	CMprofile,
489a747e4fSDavid du Colombier 	CMstart,
499a747e4fSDavid du Colombier 	CMstartstop,
50e288d156SDavid du Colombier 	CMstartsyscall,
519a747e4fSDavid du Colombier 	CMstop,
529a747e4fSDavid du Colombier 	CMwaitstop,
539a747e4fSDavid du Colombier 	CMwired,
54e288d156SDavid du Colombier 	CMtrace,
55e288d156SDavid du Colombier 	/* real time */
56e288d156SDavid du Colombier 	CMperiod,
57e288d156SDavid du Colombier 	CMdeadline,
58e288d156SDavid du Colombier 	CMcost,
59e288d156SDavid du Colombier 	CMsporadic,
60e288d156SDavid du Colombier 	CMdeadlinenotes,
61e288d156SDavid du Colombier 	CMadmit,
62179dd269SDavid du Colombier 	CMextra,
63e288d156SDavid du Colombier 	CMexpel,
642cca75a1SDavid du Colombier 	CMevent,
65e288d156SDavid du Colombier };
66e288d156SDavid du Colombier 
67e288d156SDavid du Colombier enum{
68e288d156SDavid du Colombier 	Nevents = 0x4000,
69e288d156SDavid du Colombier 	Emask = Nevents - 1,
709a747e4fSDavid du Colombier };
719a747e4fSDavid du Colombier 
729a747e4fSDavid du Colombier #define	STATSIZE	(2*KNAMELEN+12+9*12)
739a747e4fSDavid du Colombier /*
749a747e4fSDavid du Colombier  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
759a747e4fSDavid du Colombier  * particularly on shared servers.
769a747e4fSDavid du Colombier  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
779a747e4fSDavid du Colombier  */
783e12c5d1SDavid du Colombier Dirtab procdir[] =
793e12c5d1SDavid du Colombier {
80d9306527SDavid du Colombier 	"args",		{Qargs},	0,			0660,
813e12c5d1SDavid du Colombier 	"ctl",		{Qctl},		0,			0000,
829a747e4fSDavid du Colombier 	"fd",		{Qfd},		0,			0444,
837dd7cddfSDavid du Colombier 	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,
849a747e4fSDavid du Colombier 	"kregs",	{Qkregs},	sizeof(Ureg),		0400,
853e12c5d1SDavid du Colombier 	"mem",		{Qmem},		0,			0000,
863e12c5d1SDavid du Colombier 	"note",		{Qnote},	0,			0000,
8759cc4ca5SDavid du Colombier 	"noteid",	{Qnoteid},	0,			0664,
883e12c5d1SDavid du Colombier 	"notepg",	{Qnotepg},	0,			0000,
897dd7cddfSDavid du Colombier 	"ns",		{Qns},		0,			0444,
907dd7cddfSDavid du Colombier 	"proc",		{Qproc},	0,			0400,
917dd7cddfSDavid du Colombier 	"regs",		{Qregs},	sizeof(Ureg),		0000,
923e12c5d1SDavid du Colombier 	"segment",	{Qsegment},	0,			0444,
933e12c5d1SDavid du Colombier 	"status",	{Qstatus},	STATSIZE,		0444,
943e12c5d1SDavid du Colombier 	"text",		{Qtext},	0,			0000,
95219b2ee8SDavid du Colombier 	"wait",		{Qwait},	0,			0400,
967dd7cddfSDavid du Colombier 	"profile",	{Qprofile},	0,			0400,
97d1be6b08SDavid du Colombier 	"syscall",	{Qsyscall},	0,			0400,
983e12c5d1SDavid du Colombier };
993e12c5d1SDavid du Colombier 
1009a747e4fSDavid du Colombier static
1019a747e4fSDavid du Colombier Cmdtab proccmd[] = {
1029a747e4fSDavid du Colombier 	CMclose,		"close",		2,
1039a747e4fSDavid du Colombier 	CMclosefiles,		"closefiles",		1,
1049a747e4fSDavid du Colombier 	CMfixedpri,		"fixedpri",		2,
1059a747e4fSDavid du Colombier 	CMhang,			"hang",			1,
1069a747e4fSDavid du Colombier 	CMnohang,		"nohang",		1,
107b7b24591SDavid du Colombier 	CMnoswap,		"noswap",		1,
1089a747e4fSDavid du Colombier 	CMkill,			"kill",			1,
1099a747e4fSDavid du Colombier 	CMpri,			"pri",			2,
1109a747e4fSDavid du Colombier 	CMprivate,		"private",		1,
1119a747e4fSDavid du Colombier 	CMprofile,		"profile",		1,
1129a747e4fSDavid du Colombier 	CMstart,		"start",		1,
1139a747e4fSDavid du Colombier 	CMstartstop,		"startstop",		1,
114e288d156SDavid du Colombier 	CMstartsyscall,		"startsyscall",		1,
1159a747e4fSDavid du Colombier 	CMstop,			"stop",			1,
1169a747e4fSDavid du Colombier 	CMwaitstop,		"waitstop",		1,
1179a747e4fSDavid du Colombier 	CMwired,		"wired",		2,
118179dd269SDavid du Colombier 	CMtrace,		"trace",		0,
119e288d156SDavid du Colombier 	CMperiod,		"period",		2,
120e288d156SDavid du Colombier 	CMdeadline,		"deadline",		2,
121e288d156SDavid du Colombier 	CMcost,			"cost",			2,
122e288d156SDavid du Colombier 	CMsporadic,		"sporadic",		1,
123e288d156SDavid du Colombier 	CMdeadlinenotes,	"deadlinenotes",	1,
124e288d156SDavid du Colombier 	CMadmit,		"admit",		1,
125179dd269SDavid du Colombier 	CMextra,		"extra",		1,
126e288d156SDavid du Colombier 	CMexpel,		"expel",		1,
1272cca75a1SDavid du Colombier 	CMevent,		"event",		1,
1289a747e4fSDavid du Colombier };
1299a747e4fSDavid du Colombier 
1303e12c5d1SDavid du Colombier /* Segment type from portdat.h */
1319a747e4fSDavid du Colombier static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
1323e12c5d1SDavid du Colombier 
1333e12c5d1SDavid du Colombier /*
1343e12c5d1SDavid du Colombier  * Qids are, in path:
13598bee55eSDavid du Colombier  *	 5 bits of file type (qids above)
13698bee55eSDavid du Colombier  *	26 bits of process slot number + 1
1373e12c5d1SDavid du Colombier  *	     in vers,
1383e12c5d1SDavid du Colombier  *	32 bits of pid, for consistency checking
1393e12c5d1SDavid du Colombier  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
1403e12c5d1SDavid du Colombier  */
1417dd7cddfSDavid du Colombier #define	QSHIFT	5	/* location in qid of proc slot # */
1423e12c5d1SDavid du Colombier 
14398bee55eSDavid du Colombier #define	QID(q)		((((ulong)(q).path) & ((1<<QSHIFT)-1)) >> 0)
14498bee55eSDavid du Colombier #define	SLOT(q)		(((((ulong)(q).path) & ~(1UL<<31)) >> QSHIFT) - 1)
1453e12c5d1SDavid du Colombier #define	PID(q)		((q).vers)
1463e12c5d1SDavid du Colombier #define	NOTEID(q)	((q).vers)
1473e12c5d1SDavid du Colombier 
1483e12c5d1SDavid du Colombier void	procctlreq(Proc*, char*, int);
1493e12c5d1SDavid du Colombier int	procctlmemio(Proc*, ulong, int, void*, int);
1503e12c5d1SDavid du Colombier Chan*	proctext(Chan*, Proc*);
1513e12c5d1SDavid du Colombier Segment* txt2data(Proc*, Segment*);
1523e12c5d1SDavid du Colombier int	procstopped(void*);
1537dd7cddfSDavid du Colombier void	mntscan(Mntwalk*, Proc*);
1543e12c5d1SDavid du Colombier 
155e288d156SDavid du Colombier static Traceevent *tevents;
156e288d156SDavid du Colombier static Lock tlock;
157e288d156SDavid du Colombier static int topens;
158e288d156SDavid du Colombier static int tproduced, tconsumed;
1590701b922SDavid du Colombier void (*proctrace)(Proc*, int, vlong);
160e288d156SDavid du Colombier 
161a6a9e072SDavid du Colombier extern int unfair;
162a6a9e072SDavid du Colombier 
163e288d156SDavid du Colombier static void
profclock(Ureg * ur,Timer *)164e288d156SDavid du Colombier profclock(Ureg *ur, Timer *)
165e288d156SDavid du Colombier {
166e288d156SDavid du Colombier 	Tos *tos;
167e288d156SDavid du Colombier 
168e288d156SDavid du Colombier 	if(up == 0 || up->state != Running)
169e288d156SDavid du Colombier 		return;
170e288d156SDavid du Colombier 
171e288d156SDavid du Colombier 	/* user profiling clock */
172e288d156SDavid du Colombier 	if(userureg(ur)){
173e288d156SDavid du Colombier 		tos = (Tos*)(USTKTOP-sizeof(Tos));
174e288d156SDavid du Colombier 		tos->clock += TK2MS(1);
175e288d156SDavid du Colombier 		segclock(ur->pc);
176e288d156SDavid du Colombier 	}
177e288d156SDavid du Colombier }
178e288d156SDavid du Colombier 
1797dd7cddfSDavid du Colombier static int
procgen(Chan * c,char * name,Dirtab * tab,int,int s,Dir * dp)1809a747e4fSDavid du Colombier procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
1813e12c5d1SDavid du Colombier {
1823e12c5d1SDavid du Colombier 	Qid qid;
1833e12c5d1SDavid du Colombier 	Proc *p;
1849a747e4fSDavid du Colombier 	char *ename;
1857dd7cddfSDavid du Colombier 	Segment *q;
186219b2ee8SDavid du Colombier 	ulong pid, path, perm, len;
1873e12c5d1SDavid du Colombier 
1887dd7cddfSDavid du Colombier 	if(s == DEVDOTDOT){
1899a747e4fSDavid du Colombier 		mkqid(&qid, Qdir, 0, QTDIR);
1909a747e4fSDavid du Colombier 		devdir(c, qid, "#p", 0, eve, 0555, dp);
1917dd7cddfSDavid du Colombier 		return 1;
1927dd7cddfSDavid du Colombier 	}
1937dd7cddfSDavid du Colombier 
1949a747e4fSDavid du Colombier 	if(c->qid.path == Qdir){
195e288d156SDavid du Colombier 		if(s == 0){
196e288d156SDavid du Colombier 			strcpy(up->genbuf, "trace");
197e288d156SDavid du Colombier 			mkqid(&qid, Qtrace, -1, QTFILE);
198e288d156SDavid du Colombier 			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
199e288d156SDavid du Colombier 			return 1;
200e288d156SDavid du Colombier 		}
201e288d156SDavid du Colombier 
2029a747e4fSDavid du Colombier 		if(name != nil){
2039a747e4fSDavid du Colombier 			/* ignore s and use name to find pid */
2049a747e4fSDavid du Colombier 			pid = strtol(name, &ename, 10);
2059a747e4fSDavid du Colombier 			if(pid==0 || ename[0]!='\0')
2069a747e4fSDavid du Colombier 				return -1;
2079a747e4fSDavid du Colombier 			s = procindex(pid);
2089a747e4fSDavid du Colombier 			if(s < 0)
2099a747e4fSDavid du Colombier 				return -1;
210e288d156SDavid du Colombier 		}
211e288d156SDavid du Colombier 		else if(--s >= conf.nproc)
2123e12c5d1SDavid du Colombier 			return -1;
213e288d156SDavid du Colombier 
2143e12c5d1SDavid du Colombier 		p = proctab(s);
2153e12c5d1SDavid du Colombier 		pid = p->pid;
2163e12c5d1SDavid du Colombier 		if(pid == 0)
2173e12c5d1SDavid du Colombier 			return 0;
218*4e3613abSDavid du Colombier 		snprint(up->genbuf, sizeof up->genbuf, "%lud", pid);
2199a747e4fSDavid du Colombier 		/*
2209a747e4fSDavid du Colombier 		 * String comparison is done in devwalk so name must match its formatted pid
2219a747e4fSDavid du Colombier 		*/
2229a747e4fSDavid du Colombier 		if(name != nil && strcmp(name, up->genbuf) != 0)
2239a747e4fSDavid du Colombier 			return -1;
2249a747e4fSDavid du Colombier 		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
2259a747e4fSDavid du Colombier 		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
2263e12c5d1SDavid du Colombier 		return 1;
2273e12c5d1SDavid du Colombier 	}
228e288d156SDavid du Colombier 	if(c->qid.path == Qtrace){
229e288d156SDavid du Colombier 		strcpy(up->genbuf, "trace");
230e288d156SDavid du Colombier 		mkqid(&qid, Qtrace, -1, QTFILE);
231e288d156SDavid du Colombier 		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
232e288d156SDavid du Colombier 		return 1;
233e288d156SDavid du Colombier 	}
234c957ad6aSDavid du Colombier 	if(s >= nelem(procdir))
2353e12c5d1SDavid du Colombier 		return -1;
2363e12c5d1SDavid du Colombier 	if(tab)
2373e12c5d1SDavid du Colombier 		panic("procgen");
2383e12c5d1SDavid du Colombier 
2393e12c5d1SDavid du Colombier 	tab = &procdir[s];
2409a747e4fSDavid du Colombier 	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
2413e12c5d1SDavid du Colombier 
242717772fdSDavid du Colombier 	/* p->procmode determines default mode for files in /proc */
2433e12c5d1SDavid du Colombier 	p = proctab(SLOT(c->qid));
2443e12c5d1SDavid du Colombier 	perm = tab->perm;
2453e12c5d1SDavid du Colombier 	if(perm == 0)
2463e12c5d1SDavid du Colombier 		perm = p->procmode;
24759cc4ca5SDavid du Colombier 	else	/* just copy read bits */
24859cc4ca5SDavid du Colombier 		perm |= p->procmode & 0444;
2493e12c5d1SDavid du Colombier 
250219b2ee8SDavid du Colombier 	len = tab->length;
2517dd7cddfSDavid du Colombier 	switch(QID(c->qid)) {
2527dd7cddfSDavid du Colombier 	case Qwait:
2539a747e4fSDavid du Colombier 		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
2547dd7cddfSDavid du Colombier 		break;
2557dd7cddfSDavid du Colombier 	case Qprofile:
2567dd7cddfSDavid du Colombier 		q = p->seg[TSEG];
2577dd7cddfSDavid du Colombier 		if(q && q->profile) {
2587dd7cddfSDavid du Colombier 			len = (q->top-q->base)>>LRESPROF;
2597dd7cddfSDavid du Colombier 			len *= sizeof(*q->profile);
2607dd7cddfSDavid du Colombier 		}
2617dd7cddfSDavid du Colombier 		break;
2627dd7cddfSDavid du Colombier 	}
263219b2ee8SDavid du Colombier 
2649a747e4fSDavid du Colombier 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
265219b2ee8SDavid du Colombier 	devdir(c, qid, tab->name, len, p->user, perm, dp);
2663e12c5d1SDavid du Colombier 	return 1;
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
2697dd7cddfSDavid du Colombier static void
_proctrace(Proc * p,Tevent etype,vlong ts)2700701b922SDavid du Colombier _proctrace(Proc* p, Tevent etype, vlong ts)
271e288d156SDavid du Colombier {
272e288d156SDavid du Colombier 	Traceevent *te;
273e288d156SDavid du Colombier 
274da51d93aSDavid du Colombier 	if (p->trace == 0 || topens == 0 ||
275da51d93aSDavid du Colombier 		tproduced - tconsumed >= Nevents)
276e288d156SDavid du Colombier 		return;
277e288d156SDavid du Colombier 
278e288d156SDavid du Colombier 	te = &tevents[tproduced&Emask];
279e288d156SDavid du Colombier 	te->pid = p->pid;
280e288d156SDavid du Colombier 	te->etype = etype;
2810701b922SDavid du Colombier 	if (ts == 0)
282e288d156SDavid du Colombier 		te->time = todget(nil);
2830701b922SDavid du Colombier 	else
2840701b922SDavid du Colombier 		te->time = ts;
285e288d156SDavid du Colombier 	tproduced++;
286e288d156SDavid du Colombier }
287e288d156SDavid du Colombier 
288e288d156SDavid du Colombier static void
procinit(void)2893e12c5d1SDavid du Colombier procinit(void)
2903e12c5d1SDavid du Colombier {
29198bee55eSDavid du Colombier 	if(conf.nproc >= (1<<(31-QSHIFT))-1)
2923e12c5d1SDavid du Colombier 		print("warning: too many procs for devproc\n");
293e288d156SDavid du Colombier 	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
2943e12c5d1SDavid du Colombier }
2953e12c5d1SDavid du Colombier 
2967dd7cddfSDavid du Colombier static Chan*
procattach(char * spec)2973e12c5d1SDavid du Colombier procattach(char *spec)
2983e12c5d1SDavid du Colombier {
2993e12c5d1SDavid du Colombier 	return devattach('p', spec);
3003e12c5d1SDavid du Colombier }
3013e12c5d1SDavid du Colombier 
3029a747e4fSDavid du Colombier static Walkqid*
procwalk(Chan * c,Chan * nc,char ** name,int nname)3039a747e4fSDavid du Colombier procwalk(Chan *c, Chan *nc, char **name, int nname)
3043e12c5d1SDavid du Colombier {
3059a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, 0, 0, procgen);
3063e12c5d1SDavid du Colombier }
3073e12c5d1SDavid du Colombier 
3089a747e4fSDavid du Colombier static int
procstat(Chan * c,uchar * db,int n)3099a747e4fSDavid du Colombier procstat(Chan *c, uchar *db, int n)
3103e12c5d1SDavid du Colombier {
3119a747e4fSDavid du Colombier 	return devstat(c, db, n, 0, 0, procgen);
3129a747e4fSDavid du Colombier }
3139a747e4fSDavid du Colombier 
3149a747e4fSDavid du Colombier /*
3159a747e4fSDavid du Colombier  *  none can't read or write state on other
3169a747e4fSDavid du Colombier  *  processes.  This is to contain access of
3179a747e4fSDavid du Colombier  *  servers running as none should they be
3189a747e4fSDavid du Colombier  *  subverted by, for example, a stack attack.
3199a747e4fSDavid du Colombier  */
3209a747e4fSDavid du Colombier static void
nonone(Proc * p)3219a747e4fSDavid du Colombier nonone(Proc *p)
3229a747e4fSDavid du Colombier {
3239a747e4fSDavid du Colombier 	if(p == up)
3249a747e4fSDavid du Colombier 		return;
3259a747e4fSDavid du Colombier 	if(strcmp(up->user, "none") != 0)
3269a747e4fSDavid du Colombier 		return;
3279a747e4fSDavid du Colombier 	if(iseve())
3289a747e4fSDavid du Colombier 		return;
3299a747e4fSDavid du Colombier 	error(Eperm);
3303e12c5d1SDavid du Colombier }
3313e12c5d1SDavid du Colombier 
3327dd7cddfSDavid du Colombier static Chan*
procopen(Chan * c,int omode)3333e12c5d1SDavid du Colombier procopen(Chan *c, int omode)
3343e12c5d1SDavid du Colombier {
3353e12c5d1SDavid du Colombier 	Proc *p;
3363e12c5d1SDavid du Colombier 	Pgrp *pg;
3373e12c5d1SDavid du Colombier 	Chan *tc;
3387dd7cddfSDavid du Colombier 	int pid;
3393e12c5d1SDavid du Colombier 
3409a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
3413e12c5d1SDavid du Colombier 		return devopen(c, omode, 0, 0, procgen);
3423e12c5d1SDavid du Colombier 
343e288d156SDavid du Colombier 	if(QID(c->qid) == Qtrace){
344e288d156SDavid du Colombier 		if (omode != OREAD)
345e288d156SDavid du Colombier 			error(Eperm);
346e288d156SDavid du Colombier 		lock(&tlock);
347e288d156SDavid du Colombier 		if (waserror()){
348e288d156SDavid du Colombier 			unlock(&tlock);
349e288d156SDavid du Colombier 			nexterror();
350e288d156SDavid du Colombier 		}
351e288d156SDavid du Colombier 		if (topens > 0)
352e288d156SDavid du Colombier 			error("already open");
353e288d156SDavid du Colombier 		topens++;
354e288d156SDavid du Colombier 		if (tevents == nil){
355e288d156SDavid du Colombier 			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
356e288d156SDavid du Colombier 			if(tevents == nil)
357e288d156SDavid du Colombier 				error(Enomem);
358e288d156SDavid du Colombier 			tproduced = tconsumed = 0;
359e288d156SDavid du Colombier 		}
360e288d156SDavid du Colombier 		proctrace = _proctrace;
361e288d156SDavid du Colombier 		unlock(&tlock);
362e288d156SDavid du Colombier 		poperror();
363e288d156SDavid du Colombier 
364e288d156SDavid du Colombier 		c->mode = openmode(omode);
365e288d156SDavid du Colombier 		c->flag |= COPEN;
366e288d156SDavid du Colombier 		c->offset = 0;
367e288d156SDavid du Colombier 		return c;
368e288d156SDavid du Colombier 	}
369e288d156SDavid du Colombier 
3703e12c5d1SDavid du Colombier 	p = proctab(SLOT(c->qid));
3717dd7cddfSDavid du Colombier 	qlock(&p->debug);
3727dd7cddfSDavid du Colombier 	if(waserror()){
3737dd7cddfSDavid du Colombier 		qunlock(&p->debug);
3747dd7cddfSDavid du Colombier 		nexterror();
3757dd7cddfSDavid du Colombier 	}
3767dd7cddfSDavid du Colombier 	pid = PID(c->qid);
3777dd7cddfSDavid du Colombier 	if(p->pid != pid)
3783e12c5d1SDavid du Colombier 		error(Eprocdied);
3793e12c5d1SDavid du Colombier 
3803e12c5d1SDavid du Colombier 	omode = openmode(omode);
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier 	switch(QID(c->qid)){
3833e12c5d1SDavid du Colombier 	case Qtext:
3847dd7cddfSDavid du Colombier 		if(omode != OREAD)
3857dd7cddfSDavid du Colombier 			error(Eperm);
3863e12c5d1SDavid du Colombier 		tc = proctext(c, p);
3873e12c5d1SDavid du Colombier 		tc->offset = 0;
3887dd7cddfSDavid du Colombier 		qunlock(&p->debug);
3897dd7cddfSDavid du Colombier 		poperror();
39009474398SDavid du Colombier 		cclose(c);
3913e12c5d1SDavid du Colombier 		return tc;
3923e12c5d1SDavid du Colombier 
3937dd7cddfSDavid du Colombier 	case Qproc:
3947dd7cddfSDavid du Colombier 	case Qkregs:
3957dd7cddfSDavid du Colombier 	case Qsegment:
3967dd7cddfSDavid du Colombier 	case Qprofile:
3977dd7cddfSDavid du Colombier 	case Qfd:
3987dd7cddfSDavid du Colombier 		if(omode != OREAD)
3997dd7cddfSDavid du Colombier 			error(Eperm);
4007dd7cddfSDavid du Colombier 		break;
4017dd7cddfSDavid du Colombier 
4029a747e4fSDavid du Colombier 	case Qnote:
403da51d93aSDavid du Colombier 		if(p->privatemem)
404da51d93aSDavid du Colombier 			error(Eperm);
405da51d93aSDavid du Colombier 		break;
406da51d93aSDavid du Colombier 
407da51d93aSDavid du Colombier 	case Qmem:
4089a747e4fSDavid du Colombier 	case Qctl:
4099a747e4fSDavid du Colombier 		if(p->privatemem)
4109a747e4fSDavid du Colombier 			error(Eperm);
411da51d93aSDavid du Colombier 		nonone(p);
412da51d93aSDavid du Colombier 		break;
413da51d93aSDavid du Colombier 
4149a747e4fSDavid du Colombier 	case Qargs:
4159a747e4fSDavid du Colombier 	case Qnoteid:
4163e12c5d1SDavid du Colombier 	case Qstatus:
417219b2ee8SDavid du Colombier 	case Qwait:
4187dd7cddfSDavid du Colombier 	case Qregs:
4197dd7cddfSDavid du Colombier 	case Qfpregs:
420d1be6b08SDavid du Colombier 	case Qsyscall:
4219a747e4fSDavid du Colombier 		nonone(p);
4227dd7cddfSDavid du Colombier 		break;
4237dd7cddfSDavid du Colombier 
4247dd7cddfSDavid du Colombier 	case Qns:
4257dd7cddfSDavid du Colombier 		if(omode != OREAD)
4267dd7cddfSDavid du Colombier 			error(Eperm);
4277dd7cddfSDavid du Colombier 		c->aux = malloc(sizeof(Mntwalk));
4283e12c5d1SDavid du Colombier 		break;
4293e12c5d1SDavid du Colombier 
4303e12c5d1SDavid du Colombier 	case Qnotepg:
4319a747e4fSDavid du Colombier 		nonone(p);
4327dd7cddfSDavid du Colombier 		pg = p->pgrp;
4337dd7cddfSDavid du Colombier 		if(pg == nil)
4347dd7cddfSDavid du Colombier 			error(Eprocdied);
4353e12c5d1SDavid du Colombier 		if(omode!=OWRITE || pg->pgrpid == 1)
4363e12c5d1SDavid du Colombier 			error(Eperm);
4373e12c5d1SDavid du Colombier 		c->pgrpid.path = pg->pgrpid+1;
4383e12c5d1SDavid du Colombier 		c->pgrpid.vers = p->noteid;
4393e12c5d1SDavid du Colombier 		break;
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	default:
442e464ed1aSDavid du Colombier 		pprint("procopen %#lux\n", QID(c->qid));
4433e12c5d1SDavid du Colombier 		error(Egreg);
4443e12c5d1SDavid du Colombier 	}
4453e12c5d1SDavid du Colombier 
4463e12c5d1SDavid du Colombier 	/* Affix pid to qid */
4473e12c5d1SDavid du Colombier 	if(p->state != Dead)
4483e12c5d1SDavid du Colombier 		c->qid.vers = p->pid;
4493e12c5d1SDavid du Colombier 
4507dd7cddfSDavid du Colombier 	/* make sure the process slot didn't get reallocated while we were playing */
4517dd7cddfSDavid du Colombier 	coherence();
4527dd7cddfSDavid du Colombier 	if(p->pid != pid)
4537dd7cddfSDavid du Colombier 		error(Eprocdied);
4547dd7cddfSDavid du Colombier 
4557dd7cddfSDavid du Colombier 	tc = devopen(c, omode, 0, 0, procgen);
4567dd7cddfSDavid du Colombier 	qunlock(&p->debug);
4577dd7cddfSDavid du Colombier 	poperror();
4587dd7cddfSDavid du Colombier 
4597dd7cddfSDavid du Colombier 	return tc;
4603e12c5d1SDavid du Colombier }
4613e12c5d1SDavid du Colombier 
4629a747e4fSDavid du Colombier static int
procwstat(Chan * c,uchar * db,int n)4639a747e4fSDavid du Colombier procwstat(Chan *c, uchar *db, int n)
4643e12c5d1SDavid du Colombier {
4653e12c5d1SDavid du Colombier 	Proc *p;
4669a747e4fSDavid du Colombier 	Dir *d;
4673e12c5d1SDavid du Colombier 
4689a747e4fSDavid du Colombier 	if(c->qid.type&QTDIR)
4693e12c5d1SDavid du Colombier 		error(Eperm);
4703e12c5d1SDavid du Colombier 
471e288d156SDavid du Colombier 	if(QID(c->qid) == Qtrace)
472e288d156SDavid du Colombier 		return devwstat(c, db, n);
473e288d156SDavid du Colombier 
4743e12c5d1SDavid du Colombier 	p = proctab(SLOT(c->qid));
4759a747e4fSDavid du Colombier 	nonone(p);
4769a747e4fSDavid du Colombier 	d = nil;
4777dd7cddfSDavid du Colombier 	if(waserror()){
4789a747e4fSDavid du Colombier 		free(d);
4797dd7cddfSDavid du Colombier 		qunlock(&p->debug);
4807dd7cddfSDavid du Colombier 		nexterror();
4817dd7cddfSDavid du Colombier 	}
4827dd7cddfSDavid du Colombier 	qlock(&p->debug);
4837dd7cddfSDavid du Colombier 
4843e12c5d1SDavid du Colombier 	if(p->pid != PID(c->qid))
4853e12c5d1SDavid du Colombier 		error(Eprocdied);
4863e12c5d1SDavid du Colombier 
4877dd7cddfSDavid du Colombier 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
4883e12c5d1SDavid du Colombier 		error(Eperm);
4893e12c5d1SDavid du Colombier 
4909a747e4fSDavid du Colombier 	d = smalloc(sizeof(Dir)+n);
4919a747e4fSDavid du Colombier 	n = convM2D(db, n, &d[0], (char*)&d[1]);
4929a747e4fSDavid du Colombier 	if(n == 0)
4939a747e4fSDavid du Colombier 		error(Eshortstat);
4949a747e4fSDavid du Colombier 	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
4957dd7cddfSDavid du Colombier 		if(strcmp(up->user, eve) != 0)
4967dd7cddfSDavid du Colombier 			error(Eperm);
4979a747e4fSDavid du Colombier 		else
4989a747e4fSDavid du Colombier 			kstrdup(&p->user, d->uid);
4997dd7cddfSDavid du Colombier 	}
500717772fdSDavid du Colombier 	/* p->procmode determines default mode for files in /proc */
5019a747e4fSDavid du Colombier 	if(d->mode != ~0UL)
5029a747e4fSDavid du Colombier 		p->procmode = d->mode&0777;
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 	poperror();
5059a747e4fSDavid du Colombier 	free(d);
5067dd7cddfSDavid du Colombier 	qunlock(&p->debug);
5079a747e4fSDavid du Colombier 	return n;
5083e12c5d1SDavid du Colombier }
5093e12c5d1SDavid du Colombier 
5109a747e4fSDavid du Colombier 
51180ee5cbfSDavid du Colombier static long
procoffset(long offset,char * va,int * np)51280ee5cbfSDavid du Colombier procoffset(long offset, char *va, int *np)
51380ee5cbfSDavid du Colombier {
51480ee5cbfSDavid du Colombier 	if(offset > 0) {
51580ee5cbfSDavid du Colombier 		offset -= *np;
51680ee5cbfSDavid du Colombier 		if(offset < 0) {
51780ee5cbfSDavid du Colombier 			memmove(va, va+*np+offset, -offset);
51880ee5cbfSDavid du Colombier 			*np = -offset;
51980ee5cbfSDavid du Colombier 		}
52080ee5cbfSDavid du Colombier 		else
52180ee5cbfSDavid du Colombier 			*np = 0;
52280ee5cbfSDavid du Colombier 	}
52380ee5cbfSDavid du Colombier 	return offset;
52480ee5cbfSDavid du Colombier }
52580ee5cbfSDavid du Colombier 
5267dd7cddfSDavid du Colombier static int
procqidwidth(Chan * c)5279a747e4fSDavid du Colombier procqidwidth(Chan *c)
5289a747e4fSDavid du Colombier {
5299a747e4fSDavid du Colombier 	char buf[32];
5309a747e4fSDavid du Colombier 
531*4e3613abSDavid du Colombier 	return snprint(buf, sizeof buf, "%lud", c->qid.vers);
5329a747e4fSDavid du Colombier }
5339a747e4fSDavid du Colombier 
5349a747e4fSDavid du Colombier int
procfdprint(Chan * c,int fd,int w,char * s,int ns)5359a747e4fSDavid du Colombier procfdprint(Chan *c, int fd, int w, char *s, int ns)
5369a747e4fSDavid du Colombier {
5379a747e4fSDavid du Colombier 	int n;
5389a747e4fSDavid du Colombier 
5399a747e4fSDavid du Colombier 	if(w == 0)
5409a747e4fSDavid du Colombier 		w = procqidwidth(c);
5419a747e4fSDavid du Colombier 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
5429a747e4fSDavid du Colombier 		fd,
5439a747e4fSDavid du Colombier 		&"r w rw"[(c->mode&3)<<1],
5449a747e4fSDavid du Colombier 		devtab[c->type]->dc, c->dev,
5459a747e4fSDavid du Colombier 		c->qid.path, w, c->qid.vers, c->qid.type,
5464afe124fSDavid du Colombier 		c->iounit, c->offset, c->path->s);
5479a747e4fSDavid du Colombier 	return n;
5489a747e4fSDavid du Colombier }
5499a747e4fSDavid du Colombier 
5509a747e4fSDavid du Colombier static int
procfds(Proc * p,char * va,int count,long offset)5517dd7cddfSDavid du Colombier procfds(Proc *p, char *va, int count, long offset)
5527dd7cddfSDavid du Colombier {
5537dd7cddfSDavid du Colombier 	Fgrp *f;
5547dd7cddfSDavid du Colombier 	Chan *c;
5559a747e4fSDavid du Colombier 	char buf[256];
5569a747e4fSDavid du Colombier 	int n, i, w, ww;
5579a747e4fSDavid du Colombier 	char *a;
5589a747e4fSDavid du Colombier 
5599a747e4fSDavid du Colombier 	/* print to buf to avoid holding fgrp lock while writing to user space */
5609a747e4fSDavid du Colombier 	if(count > sizeof buf)
5619a747e4fSDavid du Colombier 		count = sizeof buf;
5629a747e4fSDavid du Colombier 	a = buf;
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier 	qlock(&p->debug);
5657dd7cddfSDavid du Colombier 	f = p->fgrp;
5667dd7cddfSDavid du Colombier 	if(f == nil){
5677dd7cddfSDavid du Colombier 		qunlock(&p->debug);
5687dd7cddfSDavid du Colombier 		return 0;
5697dd7cddfSDavid du Colombier 	}
5707dd7cddfSDavid du Colombier 	lock(f);
5717dd7cddfSDavid du Colombier 	if(waserror()){
5727dd7cddfSDavid du Colombier 		unlock(f);
5737dd7cddfSDavid du Colombier 		qunlock(&p->debug);
5747dd7cddfSDavid du Colombier 		nexterror();
5757dd7cddfSDavid du Colombier 	}
5767dd7cddfSDavid du Colombier 
5774afe124fSDavid du Colombier 	n = readstr(0, a, count, p->dot->path->s);
5789a747e4fSDavid du Colombier 	n += snprint(a+n, count-n, "\n");
5799a747e4fSDavid du Colombier 	offset = procoffset(offset, a, &n);
5809a747e4fSDavid du Colombier 	/* compute width of qid.path */
5819a747e4fSDavid du Colombier 	w = 0;
5827dd7cddfSDavid du Colombier 	for(i = 0; i <= f->maxfd; i++) {
5837dd7cddfSDavid du Colombier 		c = f->fd[i];
5847dd7cddfSDavid du Colombier 		if(c == nil)
5857dd7cddfSDavid du Colombier 			continue;
5869a747e4fSDavid du Colombier 		ww = procqidwidth(c);
5879a747e4fSDavid du Colombier 		if(ww > w)
5889a747e4fSDavid du Colombier 			w = ww;
5899a747e4fSDavid du Colombier 	}
5909a747e4fSDavid du Colombier 	for(i = 0; i <= f->maxfd; i++) {
5919a747e4fSDavid du Colombier 		c = f->fd[i];
5929a747e4fSDavid du Colombier 		if(c == nil)
5939a747e4fSDavid du Colombier 			continue;
5949a747e4fSDavid du Colombier 		n += procfdprint(c, i, w, a+n, count-n);
5959a747e4fSDavid du Colombier 		offset = procoffset(offset, a, &n);
5967dd7cddfSDavid du Colombier 	}
5977dd7cddfSDavid du Colombier 	unlock(f);
5987dd7cddfSDavid du Colombier 	qunlock(&p->debug);
5997dd7cddfSDavid du Colombier 	poperror();
6007dd7cddfSDavid du Colombier 
6019a747e4fSDavid du Colombier 	/* copy result to user space, now that locks are released */
6029a747e4fSDavid du Colombier 	memmove(va, buf, n);
6039a747e4fSDavid du Colombier 
6047dd7cddfSDavid du Colombier 	return n;
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier 
6077dd7cddfSDavid du Colombier static void
procclose(Chan * c)6083e12c5d1SDavid du Colombier procclose(Chan * c)
6093e12c5d1SDavid du Colombier {
610e288d156SDavid du Colombier 	if(QID(c->qid) == Qtrace){
611e288d156SDavid du Colombier 		lock(&tlock);
612e288d156SDavid du Colombier 		if(topens > 0)
613e288d156SDavid du Colombier 			topens--;
614e288d156SDavid du Colombier 		if(topens == 0)
615e288d156SDavid du Colombier 			proctrace = nil;
616e288d156SDavid du Colombier 		unlock(&tlock);
617e288d156SDavid du Colombier 	}
6187dd7cddfSDavid du Colombier 	if(QID(c->qid) == Qns && c->aux != 0)
6197dd7cddfSDavid du Colombier 		free(c->aux);
6203e12c5d1SDavid du Colombier }
6213e12c5d1SDavid du Colombier 
6227dd7cddfSDavid du Colombier static void
int2flag(int flag,char * s)6237dd7cddfSDavid du Colombier int2flag(int flag, char *s)
6243e12c5d1SDavid du Colombier {
6257dd7cddfSDavid du Colombier 	if(flag == 0){
6267dd7cddfSDavid du Colombier 		*s = '\0';
6277dd7cddfSDavid du Colombier 		return;
6287dd7cddfSDavid du Colombier 	}
6297dd7cddfSDavid du Colombier 	*s++ = '-';
6307dd7cddfSDavid du Colombier 	if(flag & MAFTER)
6317dd7cddfSDavid du Colombier 		*s++ = 'a';
6327dd7cddfSDavid du Colombier 	if(flag & MBEFORE)
6337dd7cddfSDavid du Colombier 		*s++ = 'b';
6347dd7cddfSDavid du Colombier 	if(flag & MCREATE)
6357dd7cddfSDavid du Colombier 		*s++ = 'c';
6367dd7cddfSDavid du Colombier 	if(flag & MCACHE)
6377dd7cddfSDavid du Colombier 		*s++ = 'C';
6387dd7cddfSDavid du Colombier 	*s = '\0';
6397dd7cddfSDavid du Colombier }
6407dd7cddfSDavid du Colombier 
6419a747e4fSDavid du Colombier static int
procargs(Proc * p,char * buf,int nbuf)6429a747e4fSDavid du Colombier procargs(Proc *p, char *buf, int nbuf)
6439a747e4fSDavid du Colombier {
6449a747e4fSDavid du Colombier 	int j, k, m;
6459a747e4fSDavid du Colombier 	char *a;
6469a747e4fSDavid du Colombier 	int n;
6479a747e4fSDavid du Colombier 
6489a747e4fSDavid du Colombier 	a = p->args;
649d9306527SDavid du Colombier 	if(p->setargs){
650d9306527SDavid du Colombier 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
651d9306527SDavid du Colombier 		return strlen(buf);
652d9306527SDavid du Colombier 	}
6539a747e4fSDavid du Colombier 	n = p->nargs;
6549a747e4fSDavid du Colombier 	for(j = 0; j < nbuf - 1; j += m){
655d9306527SDavid du Colombier 		if(n <= 0)
6569a747e4fSDavid du Colombier 			break;
6579a747e4fSDavid du Colombier 		if(j != 0)
6589a747e4fSDavid du Colombier 			buf[j++] = ' ';
6599a747e4fSDavid du Colombier 		m = snprint(buf+j, nbuf-j, "%q",  a);
6609a747e4fSDavid du Colombier 		k = strlen(a) + 1;
6619a747e4fSDavid du Colombier 		a += k;
6629a747e4fSDavid du Colombier 		n -= k;
6639a747e4fSDavid du Colombier 	}
6649a747e4fSDavid du Colombier 	return j;
6659a747e4fSDavid du Colombier }
6669a747e4fSDavid du Colombier 
667e288d156SDavid du Colombier static int
eventsavailable(void *)668e288d156SDavid du Colombier eventsavailable(void *)
669e288d156SDavid du Colombier {
670e288d156SDavid du Colombier 	return tproduced > tconsumed;
671e288d156SDavid du Colombier }
672e288d156SDavid du Colombier 
6737dd7cddfSDavid du Colombier static long
procread(Chan * c,void * va,long n,vlong off)6747dd7cddfSDavid du Colombier procread(Chan *c, void *va, long n, vlong off)
6757dd7cddfSDavid du Colombier {
676208510e1SDavid du Colombier 	/* NSEG*32 was too small for worst cases */
677208510e1SDavid du Colombier 	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
6784de34a7eSDavid du Colombier 	int i, j, m, navail, ne, pid, rsize;
6793e12c5d1SDavid du Colombier 	long l;
6807dd7cddfSDavid du Colombier 	uchar *rptr;
6814de34a7eSDavid du Colombier 	ulong offset;
6824de34a7eSDavid du Colombier 	Confmem *cm;
6837dd7cddfSDavid du Colombier 	Mntwalk *mw;
6844de34a7eSDavid du Colombier 	Proc *p;
6857dd7cddfSDavid du Colombier 	Segment *sg, *s;
6864de34a7eSDavid du Colombier 	Ureg kur;
6874de34a7eSDavid du Colombier 	Waitq *wq;
6884de34a7eSDavid du Colombier 
6894de34a7eSDavid du Colombier 	a = va;
6904de34a7eSDavid du Colombier 	offset = off;
6913e12c5d1SDavid du Colombier 
6929a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
6933e12c5d1SDavid du Colombier 		return devdirread(c, a, n, 0, 0, procgen);
6943e12c5d1SDavid du Colombier 
695e288d156SDavid du Colombier 	if(QID(c->qid) == Qtrace){
696e288d156SDavid du Colombier 		if(!eventsavailable(nil))
697e288d156SDavid du Colombier 			return 0;
698e288d156SDavid du Colombier 
699e288d156SDavid du Colombier 		rptr = (uchar*)va;
700e288d156SDavid du Colombier 		navail = tproduced - tconsumed;
701e288d156SDavid du Colombier 		if(navail > n / sizeof(Traceevent))
702e288d156SDavid du Colombier 			navail = n / sizeof(Traceevent);
703e288d156SDavid du Colombier 		while(navail > 0) {
704e288d156SDavid du Colombier 			ne = ((tconsumed & Emask) + navail > Nevents)?
705e288d156SDavid du Colombier 					Nevents - (tconsumed & Emask): navail;
706e288d156SDavid du Colombier 			memmove(rptr, &tevents[tconsumed & Emask],
707e288d156SDavid du Colombier 					ne * sizeof(Traceevent));
708e288d156SDavid du Colombier 
709e288d156SDavid du Colombier 			tconsumed += ne;
710e288d156SDavid du Colombier 			rptr += ne * sizeof(Traceevent);
711e288d156SDavid du Colombier 			navail -= ne;
712e288d156SDavid du Colombier 		}
713e288d156SDavid du Colombier 		return rptr - (uchar*)va;
714e288d156SDavid du Colombier 	}
715e288d156SDavid du Colombier 
7163e12c5d1SDavid du Colombier 	p = proctab(SLOT(c->qid));
7173e12c5d1SDavid du Colombier 	if(p->pid != PID(c->qid))
7183e12c5d1SDavid du Colombier 		error(Eprocdied);
7193e12c5d1SDavid du Colombier 
7203e12c5d1SDavid du Colombier 	switch(QID(c->qid)){
7219a747e4fSDavid du Colombier 	case Qargs:
722d9306527SDavid du Colombier 		qlock(&p->debug);
723cdf9e71cSDavid du Colombier 		j = procargs(p, up->genbuf, sizeof up->genbuf);
724d9306527SDavid du Colombier 		qunlock(&p->debug);
7259a747e4fSDavid du Colombier 		if(offset >= j)
7269a747e4fSDavid du Colombier 			return 0;
7279a747e4fSDavid du Colombier 		if(offset+n > j)
7289a747e4fSDavid du Colombier 			n = j-offset;
729cdf9e71cSDavid du Colombier 		memmove(a, &up->genbuf[offset], n);
7309a747e4fSDavid du Colombier 		return n;
731d1be6b08SDavid du Colombier 	case Qsyscall:
732d1be6b08SDavid du Colombier 		if(!p->syscalltrace)
733d1be6b08SDavid du Colombier 			return 0;
734d1be6b08SDavid du Colombier 		n = readstr(offset, a, n, p->syscalltrace);
735d1be6b08SDavid du Colombier 		return n;
7369a747e4fSDavid du Colombier 
7373e12c5d1SDavid du Colombier 	case Qmem:
7384de34a7eSDavid du Colombier 		if(offset < KZERO)
7397dd7cddfSDavid du Colombier 			return procctlmemio(p, offset, n, va, 1);
7403e12c5d1SDavid du Colombier 
741b7b24591SDavid du Colombier 		if(!iseve())
742b7b24591SDavid du Colombier 			error(Eperm);
743b7b24591SDavid du Colombier 
7449a747e4fSDavid du Colombier 		/* validate kernel addresses */
7453e12c5d1SDavid du Colombier 		if(offset < (ulong)end) {
7463e12c5d1SDavid du Colombier 			if(offset+n > (ulong)end)
7473e12c5d1SDavid du Colombier 				n = (ulong)end - offset;
7483e12c5d1SDavid du Colombier 			memmove(a, (char*)offset, n);
7493e12c5d1SDavid du Colombier 			return n;
7503e12c5d1SDavid du Colombier 		}
7514de34a7eSDavid du Colombier 		for(i=0; i<nelem(conf.mem); i++){
7524de34a7eSDavid du Colombier 			cm = &conf.mem[i];
75326ad7229SDavid du Colombier 			/* klimit-1 because klimit might be zero! */
75426ad7229SDavid du Colombier 			if(cm->kbase <= offset && offset <= cm->klimit-1){
75526ad7229SDavid du Colombier 				if(offset+n >= cm->klimit-1)
7564de34a7eSDavid du Colombier 					n = cm->klimit - offset;
7573e12c5d1SDavid du Colombier 				memmove(a, (char*)offset, n);
7583e12c5d1SDavid du Colombier 				return n;
7593e12c5d1SDavid du Colombier 			}
7603e12c5d1SDavid du Colombier 		}
7617dd7cddfSDavid du Colombier 		error(Ebadarg);
7629a747e4fSDavid du Colombier 
7637dd7cddfSDavid du Colombier 	case Qprofile:
7647dd7cddfSDavid du Colombier 		s = p->seg[TSEG];
7657dd7cddfSDavid du Colombier 		if(s == 0 || s->profile == 0)
7667dd7cddfSDavid du Colombier 			error("profile is off");
7677dd7cddfSDavid du Colombier 		i = (s->top-s->base)>>LRESPROF;
7687dd7cddfSDavid du Colombier 		i *= sizeof(*s->profile);
7697dd7cddfSDavid du Colombier 		if(offset >= i)
7707dd7cddfSDavid du Colombier 			return 0;
7717dd7cddfSDavid du Colombier 		if(offset+n > i)
7727dd7cddfSDavid du Colombier 			n = i - offset;
7737dd7cddfSDavid du Colombier 		memmove(a, ((char*)s->profile)+offset, n);
7747dd7cddfSDavid du Colombier 		return n;
7753e12c5d1SDavid du Colombier 
7763e12c5d1SDavid du Colombier 	case Qnote:
7773e12c5d1SDavid du Colombier 		qlock(&p->debug);
7783e12c5d1SDavid du Colombier 		if(waserror()){
7793e12c5d1SDavid du Colombier 			qunlock(&p->debug);
7803e12c5d1SDavid du Colombier 			nexterror();
7813e12c5d1SDavid du Colombier 		}
7823e12c5d1SDavid du Colombier 		if(p->pid != PID(c->qid))
7833e12c5d1SDavid du Colombier 			error(Eprocdied);
7849a747e4fSDavid du Colombier 		if(n < 1)	/* must accept at least the '\0' */
7853e12c5d1SDavid du Colombier 			error(Etoosmall);
7867dd7cddfSDavid du Colombier 		if(p->nnote == 0)
7873e12c5d1SDavid du Colombier 			n = 0;
7883e12c5d1SDavid du Colombier 		else {
7899a747e4fSDavid du Colombier 			m = strlen(p->note[0].msg) + 1;
7909a747e4fSDavid du Colombier 			if(m > n)
7919a747e4fSDavid du Colombier 				m = n;
7929a747e4fSDavid du Colombier 			memmove(va, p->note[0].msg, m);
7939a747e4fSDavid du Colombier 			((char*)va)[m-1] = '\0';
7947dd7cddfSDavid du Colombier 			p->nnote--;
7957dd7cddfSDavid du Colombier 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
7969a747e4fSDavid du Colombier 			n = m;
7973e12c5d1SDavid du Colombier 		}
7987dd7cddfSDavid du Colombier 		if(p->nnote == 0)
7993e12c5d1SDavid du Colombier 			p->notepending = 0;
8003e12c5d1SDavid du Colombier 		poperror();
8013e12c5d1SDavid du Colombier 		qunlock(&p->debug);
8023e12c5d1SDavid du Colombier 		return n;
8033e12c5d1SDavid du Colombier 
8043e12c5d1SDavid du Colombier 	case Qproc:
8053e12c5d1SDavid du Colombier 		if(offset >= sizeof(Proc))
8063e12c5d1SDavid du Colombier 			return 0;
8073e12c5d1SDavid du Colombier 		if(offset+n > sizeof(Proc))
8083e12c5d1SDavid du Colombier 			n = sizeof(Proc) - offset;
8093e12c5d1SDavid du Colombier 		memmove(a, ((char*)p)+offset, n);
8103e12c5d1SDavid du Colombier 		return n;
8113e12c5d1SDavid du Colombier 
8127dd7cddfSDavid du Colombier 	case Qregs:
8137dd7cddfSDavid du Colombier 		rptr = (uchar*)p->dbgreg;
8147dd7cddfSDavid du Colombier 		rsize = sizeof(Ureg);
8157dd7cddfSDavid du Colombier 		goto regread;
8167dd7cddfSDavid du Colombier 
8177dd7cddfSDavid du Colombier 	case Qkregs:
8187dd7cddfSDavid du Colombier 		memset(&kur, 0, sizeof(Ureg));
8197dd7cddfSDavid du Colombier 		setkernur(&kur, p);
8207dd7cddfSDavid du Colombier 		rptr = (uchar*)&kur;
8217dd7cddfSDavid du Colombier 		rsize = sizeof(Ureg);
8227dd7cddfSDavid du Colombier 		goto regread;
8237dd7cddfSDavid du Colombier 
8247dd7cddfSDavid du Colombier 	case Qfpregs:
8257dd7cddfSDavid du Colombier 		rptr = (uchar*)&p->fpsave;
8267dd7cddfSDavid du Colombier 		rsize = sizeof(FPsave);
8277dd7cddfSDavid du Colombier 	regread:
8287dd7cddfSDavid du Colombier 		if(rptr == 0)
8297dd7cddfSDavid du Colombier 			error(Enoreg);
8307dd7cddfSDavid du Colombier 		if(offset >= rsize)
8317dd7cddfSDavid du Colombier 			return 0;
8327dd7cddfSDavid du Colombier 		if(offset+n > rsize)
8337dd7cddfSDavid du Colombier 			n = rsize - offset;
8347dd7cddfSDavid du Colombier 		memmove(a, rptr+offset, n);
8357dd7cddfSDavid du Colombier 		return n;
8367dd7cddfSDavid du Colombier 
8373e12c5d1SDavid du Colombier 	case Qstatus:
8383e12c5d1SDavid du Colombier 		if(offset >= STATSIZE)
8393e12c5d1SDavid du Colombier 			return 0;
8403e12c5d1SDavid du Colombier 		if(offset+n > STATSIZE)
8413e12c5d1SDavid du Colombier 			n = STATSIZE - offset;
8423e12c5d1SDavid du Colombier 
8433e12c5d1SDavid du Colombier 		sps = p->psstate;
8443e12c5d1SDavid du Colombier 		if(sps == 0)
8453e12c5d1SDavid du Colombier 			sps = statename[p->state];
846bd389b36SDavid du Colombier 		memset(statbuf, ' ', sizeof statbuf);
847a650be7dSDavid du Colombier 		readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
848a650be7dSDavid du Colombier 		readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
849a650be7dSDavid du Colombier 		readstr(0, statbuf+2*KNAMELEN, 11, sps);
8509a747e4fSDavid du Colombier 		j = 2*KNAMELEN + 12;
8513e12c5d1SDavid du Colombier 
8523e12c5d1SDavid du Colombier 		for(i = 0; i < 6; i++) {
8533e12c5d1SDavid du Colombier 			l = p->time[i];
8543e12c5d1SDavid du Colombier 			if(i == TReal)
8553e12c5d1SDavid du Colombier 				l = MACHP(0)->ticks - l;
8563e12c5d1SDavid du Colombier 			l = TK2MS(l);
8573e12c5d1SDavid du Colombier 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
8583e12c5d1SDavid du Colombier 		}
8593e12c5d1SDavid du Colombier 		/* ignore stack, which is mostly non-existent */
8603e12c5d1SDavid du Colombier 		l = 0;
8613e12c5d1SDavid du Colombier 		for(i=1; i<NSEG; i++){
8623e12c5d1SDavid du Colombier 			s = p->seg[i];
8633e12c5d1SDavid du Colombier 			if(s)
8643e12c5d1SDavid du Colombier 				l += s->top - s->base;
8653e12c5d1SDavid du Colombier 		}
8663e12c5d1SDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
8677dd7cddfSDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
8687dd7cddfSDavid du Colombier 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
8693e12c5d1SDavid du Colombier 		memmove(a, statbuf+offset, n);
8703e12c5d1SDavid du Colombier 		return n;
8713e12c5d1SDavid du Colombier 
8723e12c5d1SDavid du Colombier 	case Qsegment:
8733e12c5d1SDavid du Colombier 		j = 0;
8747dd7cddfSDavid du Colombier 		for(i = 0; i < NSEG; i++) {
8757dd7cddfSDavid du Colombier 			sg = p->seg[i];
8767dd7cddfSDavid du Colombier 			if(sg == 0)
8777dd7cddfSDavid du Colombier 				continue;
878*4e3613abSDavid du Colombier 			j += snprint(statbuf+j, sizeof statbuf - j,
879*4e3613abSDavid du Colombier 				"%-6s %c%c %.8lux %.8lux %4ld\n",
8807dd7cddfSDavid du Colombier 				sname[sg->type&SG_TYPE],
8817dd7cddfSDavid du Colombier 				sg->type&SG_RONLY ? 'R' : ' ',
8827dd7cddfSDavid du Colombier 				sg->profile ? 'P' : ' ',
8833e12c5d1SDavid du Colombier 				sg->base, sg->top, sg->ref);
8847dd7cddfSDavid du Colombier 		}
8853e12c5d1SDavid du Colombier 		if(offset >= j)
8863e12c5d1SDavid du Colombier 			return 0;
8873e12c5d1SDavid du Colombier 		if(offset+n > j)
8883e12c5d1SDavid du Colombier 			n = j-offset;
8893e12c5d1SDavid du Colombier 		if(n == 0 && offset == 0)
8903e12c5d1SDavid du Colombier 			exhausted("segments");
8913e12c5d1SDavid du Colombier 		memmove(a, &statbuf[offset], n);
8923e12c5d1SDavid du Colombier 		return n;
893219b2ee8SDavid du Colombier 
894219b2ee8SDavid du Colombier 	case Qwait:
895219b2ee8SDavid du Colombier 		if(!canqlock(&p->qwaitr))
896219b2ee8SDavid du Colombier 			error(Einuse);
897219b2ee8SDavid du Colombier 
898219b2ee8SDavid du Colombier 		if(waserror()) {
899219b2ee8SDavid du Colombier 			qunlock(&p->qwaitr);
900219b2ee8SDavid du Colombier 			nexterror();
901219b2ee8SDavid du Colombier 		}
902219b2ee8SDavid du Colombier 
903219b2ee8SDavid du Colombier 		lock(&p->exl);
9047dd7cddfSDavid du Colombier 		if(up == p && p->nchild == 0 && p->waitq == 0) {
905219b2ee8SDavid du Colombier 			unlock(&p->exl);
906219b2ee8SDavid du Colombier 			error(Enochild);
907219b2ee8SDavid du Colombier 		}
9087dd7cddfSDavid du Colombier 		pid = p->pid;
909219b2ee8SDavid du Colombier 		while(p->waitq == 0) {
910219b2ee8SDavid du Colombier 			unlock(&p->exl);
911219b2ee8SDavid du Colombier 			sleep(&p->waitr, haswaitq, p);
9127dd7cddfSDavid du Colombier 			if(p->pid != pid)
9137dd7cddfSDavid du Colombier 				error(Eprocdied);
914219b2ee8SDavid du Colombier 			lock(&p->exl);
915219b2ee8SDavid du Colombier 		}
916219b2ee8SDavid du Colombier 		wq = p->waitq;
917219b2ee8SDavid du Colombier 		p->waitq = wq->next;
918219b2ee8SDavid du Colombier 		p->nwait--;
919219b2ee8SDavid du Colombier 		unlock(&p->exl);
920219b2ee8SDavid du Colombier 
921219b2ee8SDavid du Colombier 		qunlock(&p->qwaitr);
922219b2ee8SDavid du Colombier 		poperror();
9239a747e4fSDavid du Colombier 		n = snprint(a, n, "%d %lud %lud %lud %q",
9249a747e4fSDavid du Colombier 			wq->w.pid,
9259a747e4fSDavid du Colombier 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
9269a747e4fSDavid du Colombier 			wq->w.msg);
927219b2ee8SDavid du Colombier 		free(wq);
9289a747e4fSDavid du Colombier 		return n;
9297dd7cddfSDavid du Colombier 
9307dd7cddfSDavid du Colombier 	case Qns:
9317dd7cddfSDavid du Colombier 		qlock(&p->debug);
9327dd7cddfSDavid du Colombier 		if(waserror()){
9337dd7cddfSDavid du Colombier 			qunlock(&p->debug);
9347dd7cddfSDavid du Colombier 			nexterror();
9357dd7cddfSDavid du Colombier 		}
9367dd7cddfSDavid du Colombier 		if(p->pgrp == nil || p->pid != PID(c->qid))
9377dd7cddfSDavid du Colombier 			error(Eprocdied);
9387dd7cddfSDavid du Colombier 		mw = c->aux;
939aa72973aSDavid du Colombier 		if(mw == nil)
940aa72973aSDavid du Colombier 			error(Enomem);
9417dd7cddfSDavid du Colombier 		if(mw->cddone){
9427dd7cddfSDavid du Colombier 			qunlock(&p->debug);
9437dd7cddfSDavid du Colombier 			poperror();
9447dd7cddfSDavid du Colombier 			return 0;
9457dd7cddfSDavid du Colombier 		}
9467dd7cddfSDavid du Colombier 		mntscan(mw, p);
9477dd7cddfSDavid du Colombier 		if(mw->mh == 0){
9487dd7cddfSDavid du Colombier 			mw->cddone = 1;
9494afe124fSDavid du Colombier 			i = snprint(a, n, "cd %s\n", p->dot->path->s);
9507dd7cddfSDavid du Colombier 			qunlock(&p->debug);
9517dd7cddfSDavid du Colombier 			poperror();
9527dd7cddfSDavid du Colombier 			return i;
9537dd7cddfSDavid du Colombier 		}
9549a747e4fSDavid du Colombier 		int2flag(mw->cm->mflag, flag);
9554afe124fSDavid du Colombier 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
9567dd7cddfSDavid du Colombier 			srv = srvname(mw->cm->to->mchan);
9579a747e4fSDavid du Colombier 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
9584afe124fSDavid du Colombier 				srv==nil? mw->cm->to->mchan->path->s : srv,
9594afe124fSDavid du Colombier 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
9607dd7cddfSDavid du Colombier 			free(srv);
9617dd7cddfSDavid du Colombier 		}else
9627dd7cddfSDavid du Colombier 			i = snprint(a, n, "bind %s %s %s\n", flag,
9634afe124fSDavid du Colombier 				mw->cm->to->path->s, mw->mh->from->path->s);
9647dd7cddfSDavid du Colombier 		qunlock(&p->debug);
9657dd7cddfSDavid du Colombier 		poperror();
9667dd7cddfSDavid du Colombier 		return i;
9677dd7cddfSDavid du Colombier 
968219b2ee8SDavid du Colombier 	case Qnoteid:
969219b2ee8SDavid du Colombier 		return readnum(offset, va, n, p->noteid, NUMSIZE);
9707dd7cddfSDavid du Colombier 	case Qfd:
9717dd7cddfSDavid du Colombier 		return procfds(p, va, n, offset);
9723e12c5d1SDavid du Colombier 	}
9733e12c5d1SDavid du Colombier 	error(Egreg);
9743e12c5d1SDavid du Colombier 	return 0;		/* not reached */
9753e12c5d1SDavid du Colombier }
9763e12c5d1SDavid du Colombier 
9777dd7cddfSDavid du Colombier void
mntscan(Mntwalk * mw,Proc * p)9787dd7cddfSDavid du Colombier mntscan(Mntwalk *mw, Proc *p)
9797dd7cddfSDavid du Colombier {
9807dd7cddfSDavid du Colombier 	Pgrp *pg;
9817dd7cddfSDavid du Colombier 	Mount *t;
9827dd7cddfSDavid du Colombier 	Mhead *f;
9837dd7cddfSDavid du Colombier 	int nxt, i;
9847dd7cddfSDavid du Colombier 	ulong last, bestmid;
9853e12c5d1SDavid du Colombier 
9867dd7cddfSDavid du Colombier 	pg = p->pgrp;
9877dd7cddfSDavid du Colombier 	rlock(&pg->ns);
9887dd7cddfSDavid du Colombier 
9897dd7cddfSDavid du Colombier 	nxt = 0;
9907dd7cddfSDavid du Colombier 	bestmid = ~0;
9917dd7cddfSDavid du Colombier 
9927dd7cddfSDavid du Colombier 	last = 0;
9937dd7cddfSDavid du Colombier 	if(mw->mh)
9947dd7cddfSDavid du Colombier 		last = mw->cm->mountid;
9957dd7cddfSDavid du Colombier 
9967dd7cddfSDavid du Colombier 	for(i = 0; i < MNTHASH; i++) {
9977dd7cddfSDavid du Colombier 		for(f = pg->mnthash[i]; f; f = f->hash) {
9987dd7cddfSDavid du Colombier 			for(t = f->mount; t; t = t->next) {
9997dd7cddfSDavid du Colombier 				if(mw->mh == 0 ||
10007dd7cddfSDavid du Colombier 				  (t->mountid > last && t->mountid < bestmid)) {
10017dd7cddfSDavid du Colombier 					mw->cm = t;
10027dd7cddfSDavid du Colombier 					mw->mh = f;
10037dd7cddfSDavid du Colombier 					bestmid = mw->cm->mountid;
10047dd7cddfSDavid du Colombier 					nxt = 1;
10057dd7cddfSDavid du Colombier 				}
10067dd7cddfSDavid du Colombier 			}
10077dd7cddfSDavid du Colombier 		}
10087dd7cddfSDavid du Colombier 	}
10097dd7cddfSDavid du Colombier 	if(nxt == 0)
10107dd7cddfSDavid du Colombier 		mw->mh = 0;
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier 	runlock(&pg->ns);
10137dd7cddfSDavid du Colombier }
10147dd7cddfSDavid du Colombier 
10157dd7cddfSDavid du Colombier static long
procwrite(Chan * c,void * va,long n,vlong off)10167dd7cddfSDavid du Colombier procwrite(Chan *c, void *va, long n, vlong off)
10173e12c5d1SDavid du Colombier {
1018d9306527SDavid du Colombier 	int id, m;
1019219b2ee8SDavid du Colombier 	Proc *p, *t, *et;
1020d9306527SDavid du Colombier 	char *a, *arg, buf[ERRMAX];
10217dd7cddfSDavid du Colombier 	ulong offset = off;
10223e12c5d1SDavid du Colombier 
10237dd7cddfSDavid du Colombier 	a = va;
10249a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
10253e12c5d1SDavid du Colombier 		error(Eisdir);
10263e12c5d1SDavid du Colombier 
10273e12c5d1SDavid du Colombier 	p = proctab(SLOT(c->qid));
10283e12c5d1SDavid du Colombier 
10297dd7cddfSDavid du Colombier 	/* Use the remembered noteid in the channel rather
10307dd7cddfSDavid du Colombier 	 * than the process pgrpid
1031219b2ee8SDavid du Colombier 	 */
10323e12c5d1SDavid du Colombier 	if(QID(c->qid) == Qnotepg) {
10333e12c5d1SDavid du Colombier 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
10343e12c5d1SDavid du Colombier 		return n;
10353e12c5d1SDavid du Colombier 	}
10363e12c5d1SDavid du Colombier 
10373e12c5d1SDavid du Colombier 	qlock(&p->debug);
10383e12c5d1SDavid du Colombier 	if(waserror()){
10393e12c5d1SDavid du Colombier 		qunlock(&p->debug);
10403e12c5d1SDavid du Colombier 		nexterror();
10413e12c5d1SDavid du Colombier 	}
10423e12c5d1SDavid du Colombier 	if(p->pid != PID(c->qid))
10433e12c5d1SDavid du Colombier 		error(Eprocdied);
10443e12c5d1SDavid du Colombier 
10453e12c5d1SDavid du Colombier 	switch(QID(c->qid)){
1046d9306527SDavid du Colombier 	case Qargs:
1047d9306527SDavid du Colombier 		if(n == 0)
1048d9306527SDavid du Colombier 			error(Eshort);
1049d9306527SDavid du Colombier 		if(n >= ERRMAX)
1050d9306527SDavid du Colombier 			error(Etoobig);
1051d9306527SDavid du Colombier 		arg = malloc(n+1);
1052d9306527SDavid du Colombier 		if(arg == nil)
1053d9306527SDavid du Colombier 			error(Enomem);
1054d9306527SDavid du Colombier 		memmove(arg, va, n);
1055d9306527SDavid du Colombier 		m = n;
1056d9306527SDavid du Colombier 		if(arg[m-1] != 0)
1057d9306527SDavid du Colombier 			arg[m++] = 0;
1058d9306527SDavid du Colombier 		free(p->args);
1059d9306527SDavid du Colombier 		p->nargs = m;
1060d9306527SDavid du Colombier 		p->args = arg;
1061d9306527SDavid du Colombier 		p->setargs = 1;
1062d9306527SDavid du Colombier 		break;
1063d9306527SDavid du Colombier 
10643e12c5d1SDavid du Colombier 	case Qmem:
10653e12c5d1SDavid du Colombier 		if(p->state != Stopped)
10663e12c5d1SDavid du Colombier 			error(Ebadctl);
10673e12c5d1SDavid du Colombier 
10683e12c5d1SDavid du Colombier 		n = procctlmemio(p, offset, n, va, 0);
10693e12c5d1SDavid du Colombier 		break;
10703e12c5d1SDavid du Colombier 
10717dd7cddfSDavid du Colombier 	case Qregs:
10727dd7cddfSDavid du Colombier 		if(offset >= sizeof(Ureg))
107309a9ed3fSDavid du Colombier 			n = 0;
107409a9ed3fSDavid du Colombier 		else if(offset+n > sizeof(Ureg))
10757dd7cddfSDavid du Colombier 			n = sizeof(Ureg) - offset;
10767dd7cddfSDavid du Colombier 		if(p->dbgreg == 0)
10777dd7cddfSDavid du Colombier 			error(Enoreg);
10787dd7cddfSDavid du Colombier 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
10797dd7cddfSDavid du Colombier 		break;
10807dd7cddfSDavid du Colombier 
10817dd7cddfSDavid du Colombier 	case Qfpregs:
10827dd7cddfSDavid du Colombier 		if(offset >= sizeof(FPsave))
108309a9ed3fSDavid du Colombier 			n = 0;
108409a9ed3fSDavid du Colombier 		else if(offset+n > sizeof(FPsave))
10857dd7cddfSDavid du Colombier 			n = sizeof(FPsave) - offset;
10867dd7cddfSDavid du Colombier 		memmove((uchar*)&p->fpsave+offset, va, n);
10877dd7cddfSDavid du Colombier 		break;
10887dd7cddfSDavid du Colombier 
10893e12c5d1SDavid du Colombier 	case Qctl:
10903e12c5d1SDavid du Colombier 		procctlreq(p, va, n);
10913e12c5d1SDavid du Colombier 		break;
10923e12c5d1SDavid du Colombier 
10933e12c5d1SDavid du Colombier 	case Qnote:
10943e12c5d1SDavid du Colombier 		if(p->kp)
10953e12c5d1SDavid du Colombier 			error(Eperm);
10969a747e4fSDavid du Colombier 		if(n >= ERRMAX-1)
10973e12c5d1SDavid du Colombier 			error(Etoobig);
10983e12c5d1SDavid du Colombier 		memmove(buf, va, n);
10993e12c5d1SDavid du Colombier 		buf[n] = 0;
11003e12c5d1SDavid du Colombier 		if(!postnote(p, 0, buf, NUser))
11013e12c5d1SDavid du Colombier 			error("note not posted");
11023e12c5d1SDavid du Colombier 		break;
1103219b2ee8SDavid du Colombier 	case Qnoteid:
1104219b2ee8SDavid du Colombier 		id = atoi(a);
1105219b2ee8SDavid du Colombier 		if(id == p->pid) {
1106219b2ee8SDavid du Colombier 			p->noteid = id;
1107219b2ee8SDavid du Colombier 			break;
1108219b2ee8SDavid du Colombier 		}
1109219b2ee8SDavid du Colombier 		t = proctab(0);
1110219b2ee8SDavid du Colombier 		for(et = t+conf.nproc; t < et; t++) {
111111c9ee8bSDavid du Colombier 			if(t->state == Dead)
111211c9ee8bSDavid du Colombier 				continue;
1113219b2ee8SDavid du Colombier 			if(id == t->noteid) {
1114219b2ee8SDavid du Colombier 				if(strcmp(p->user, t->user) != 0)
1115219b2ee8SDavid du Colombier 					error(Eperm);
1116219b2ee8SDavid du Colombier 				p->noteid = id;
1117219b2ee8SDavid du Colombier 				break;
1118219b2ee8SDavid du Colombier 			}
1119219b2ee8SDavid du Colombier 		}
1120219b2ee8SDavid du Colombier 		if(p->noteid != id)
1121219b2ee8SDavid du Colombier 			error(Ebadarg);
1122219b2ee8SDavid du Colombier 		break;
11233e12c5d1SDavid du Colombier 	default:
11243e12c5d1SDavid du Colombier 		pprint("unknown qid in procwrite\n");
11253e12c5d1SDavid du Colombier 		error(Egreg);
11263e12c5d1SDavid du Colombier 	}
11273e12c5d1SDavid du Colombier 	poperror();
11283e12c5d1SDavid du Colombier 	qunlock(&p->debug);
11293e12c5d1SDavid du Colombier 	return n;
11303e12c5d1SDavid du Colombier }
11313e12c5d1SDavid du Colombier 
11327dd7cddfSDavid du Colombier Dev procdevtab = {
11337dd7cddfSDavid du Colombier 	'p',
11347dd7cddfSDavid du Colombier 	"proc",
11357dd7cddfSDavid du Colombier 
11367dd7cddfSDavid du Colombier 	devreset,
11377dd7cddfSDavid du Colombier 	procinit,
11389a747e4fSDavid du Colombier 	devshutdown,
11397dd7cddfSDavid du Colombier 	procattach,
11407dd7cddfSDavid du Colombier 	procwalk,
11417dd7cddfSDavid du Colombier 	procstat,
11427dd7cddfSDavid du Colombier 	procopen,
11437dd7cddfSDavid du Colombier 	devcreate,
11447dd7cddfSDavid du Colombier 	procclose,
11457dd7cddfSDavid du Colombier 	procread,
11467dd7cddfSDavid du Colombier 	devbread,
11477dd7cddfSDavid du Colombier 	procwrite,
11487dd7cddfSDavid du Colombier 	devbwrite,
11497dd7cddfSDavid du Colombier 	devremove,
11507dd7cddfSDavid du Colombier 	procwstat,
11517dd7cddfSDavid du Colombier };
11527dd7cddfSDavid du Colombier 
11533e12c5d1SDavid du Colombier Chan*
proctext(Chan * c,Proc * p)11543e12c5d1SDavid du Colombier proctext(Chan *c, Proc *p)
11553e12c5d1SDavid du Colombier {
11563e12c5d1SDavid du Colombier 	Chan *tc;
11573e12c5d1SDavid du Colombier 	Image *i;
11583e12c5d1SDavid du Colombier 	Segment *s;
11593e12c5d1SDavid du Colombier 
11603e12c5d1SDavid du Colombier 	s = p->seg[TSEG];
11613e12c5d1SDavid du Colombier 	if(s == 0)
11623e12c5d1SDavid du Colombier 		error(Enonexist);
11633e12c5d1SDavid du Colombier 	if(p->state==Dead)
11643e12c5d1SDavid du Colombier 		error(Eprocdied);
11653e12c5d1SDavid du Colombier 
11663e12c5d1SDavid du Colombier 	lock(s);
11673e12c5d1SDavid du Colombier 	i = s->image;
11683e12c5d1SDavid du Colombier 	if(i == 0) {
11693e12c5d1SDavid du Colombier 		unlock(s);
11703e12c5d1SDavid du Colombier 		error(Eprocdied);
11713e12c5d1SDavid du Colombier 	}
11723e12c5d1SDavid du Colombier 	unlock(s);
11733e12c5d1SDavid du Colombier 
11743e12c5d1SDavid du Colombier 	lock(i);
11753e12c5d1SDavid du Colombier 	if(waserror()) {
11763e12c5d1SDavid du Colombier 		unlock(i);
11773e12c5d1SDavid du Colombier 		nexterror();
11783e12c5d1SDavid du Colombier 	}
11793e12c5d1SDavid du Colombier 
11803e12c5d1SDavid du Colombier 	tc = i->c;
11813e12c5d1SDavid du Colombier 	if(tc == 0)
11823e12c5d1SDavid du Colombier 		error(Eprocdied);
11833e12c5d1SDavid du Colombier 
11843e12c5d1SDavid du Colombier 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
11857dd7cddfSDavid du Colombier 		cclose(tc);
11863e12c5d1SDavid du Colombier 		error(Eprocdied);
11873e12c5d1SDavid du Colombier 	}
11883e12c5d1SDavid du Colombier 
118909474398SDavid du Colombier 	if(p->pid != PID(c->qid)){
119009474398SDavid du Colombier 		cclose(tc);
11913e12c5d1SDavid du Colombier 		error(Eprocdied);
119209474398SDavid du Colombier 	}
11933e12c5d1SDavid du Colombier 
11943e12c5d1SDavid du Colombier 	unlock(i);
11953e12c5d1SDavid du Colombier 	poperror();
11963e12c5d1SDavid du Colombier 
11973e12c5d1SDavid du Colombier 	return tc;
11983e12c5d1SDavid du Colombier }
11993e12c5d1SDavid du Colombier 
12003e12c5d1SDavid du Colombier void
procstopwait(Proc * p,int ctl)12013e12c5d1SDavid du Colombier procstopwait(Proc *p, int ctl)
12023e12c5d1SDavid du Colombier {
12033e12c5d1SDavid du Colombier 	int pid;
12043e12c5d1SDavid du Colombier 
12053e12c5d1SDavid du Colombier 	if(p->pdbg)
12063e12c5d1SDavid du Colombier 		error(Einuse);
12079a747e4fSDavid du Colombier 	if(procstopped(p) || p->state == Broken)
12083e12c5d1SDavid du Colombier 		return;
12093e12c5d1SDavid du Colombier 
12103e12c5d1SDavid du Colombier 	if(ctl != 0)
12113e12c5d1SDavid du Colombier 		p->procctl = ctl;
12127dd7cddfSDavid du Colombier 	p->pdbg = up;
12133e12c5d1SDavid du Colombier 	pid = p->pid;
12143e12c5d1SDavid du Colombier 	qunlock(&p->debug);
12157dd7cddfSDavid du Colombier 	up->psstate = "Stopwait";
12163e12c5d1SDavid du Colombier 	if(waserror()) {
12173e12c5d1SDavid du Colombier 		p->pdbg = 0;
12183e12c5d1SDavid du Colombier 		qlock(&p->debug);
12193e12c5d1SDavid du Colombier 		nexterror();
12203e12c5d1SDavid du Colombier 	}
12217dd7cddfSDavid du Colombier 	sleep(&up->sleep, procstopped, p);
12223e12c5d1SDavid du Colombier 	poperror();
12233e12c5d1SDavid du Colombier 	qlock(&p->debug);
12243e12c5d1SDavid du Colombier 	if(p->pid != pid)
12253e12c5d1SDavid du Colombier 		error(Eprocdied);
12263e12c5d1SDavid du Colombier }
12273e12c5d1SDavid du Colombier 
12289a747e4fSDavid du Colombier static void
procctlcloseone(Proc * p,Fgrp * f,int fd)12299a747e4fSDavid du Colombier procctlcloseone(Proc *p, Fgrp *f, int fd)
12309a747e4fSDavid du Colombier {
12319a747e4fSDavid du Colombier 	Chan *c;
12329a747e4fSDavid du Colombier 
12339a747e4fSDavid du Colombier 	c = f->fd[fd];
12349a747e4fSDavid du Colombier 	if(c == nil)
12359a747e4fSDavid du Colombier 		return;
12369a747e4fSDavid du Colombier 	f->fd[fd] = nil;
12379a747e4fSDavid du Colombier 	unlock(f);
12389a747e4fSDavid du Colombier 	qunlock(&p->debug);
12399a747e4fSDavid du Colombier 	cclose(c);
12409a747e4fSDavid du Colombier 	qlock(&p->debug);
12419a747e4fSDavid du Colombier 	lock(f);
12429a747e4fSDavid du Colombier }
12439a747e4fSDavid du Colombier 
12443e12c5d1SDavid du Colombier void
procctlclosefiles(Proc * p,int all,int fd)12459a747e4fSDavid du Colombier procctlclosefiles(Proc *p, int all, int fd)
12463e12c5d1SDavid du Colombier {
1247219b2ee8SDavid du Colombier 	int i;
124880ee5cbfSDavid du Colombier 	Fgrp *f;
124980ee5cbfSDavid du Colombier 
125080ee5cbfSDavid du Colombier 	f = p->fgrp;
125180ee5cbfSDavid du Colombier 	if(f == nil)
125280ee5cbfSDavid du Colombier 		error(Eprocdied);
12537dd7cddfSDavid du Colombier 
12547dd7cddfSDavid du Colombier 	lock(f);
12557dd7cddfSDavid du Colombier 	f->ref++;
12569a747e4fSDavid du Colombier 	if(all)
12579a747e4fSDavid du Colombier 		for(i = 0; i < f->maxfd; i++)
12589a747e4fSDavid du Colombier 			procctlcloseone(p, f, i);
12599a747e4fSDavid du Colombier 	else
12609a747e4fSDavid du Colombier 		procctlcloseone(p, f, fd);
12617dd7cddfSDavid du Colombier 	unlock(f);
12627dd7cddfSDavid du Colombier 	closefgrp(f);
12637dd7cddfSDavid du Colombier }
12647dd7cddfSDavid du Colombier 
1265e288d156SDavid du Colombier static char *
parsetime(vlong * rt,char * s)1266e288d156SDavid du Colombier parsetime(vlong *rt, char *s)
1267e288d156SDavid du Colombier {
1268e288d156SDavid du Colombier 	uvlong ticks;
1269e288d156SDavid du Colombier 	ulong l;
1270e288d156SDavid du Colombier 	char *e, *p;
1271e288d156SDavid du Colombier 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1272e288d156SDavid du Colombier 
1273e288d156SDavid du Colombier 	if (s == nil)
1274e288d156SDavid du Colombier 		return("missing value");
1275e288d156SDavid du Colombier 	ticks=strtoul(s, &e, 10);
1276e288d156SDavid du Colombier 	if (*e == '.'){
1277e288d156SDavid du Colombier 		p = e+1;
1278e288d156SDavid du Colombier 		l = strtoul(p, &e, 10);
1279e288d156SDavid du Colombier 		if(e-p > nelem(p10))
1280e288d156SDavid du Colombier 			return "too many digits after decimal point";
1281e288d156SDavid du Colombier 		if(e-p == 0)
1282e288d156SDavid du Colombier 			return "ill-formed number";
1283e288d156SDavid du Colombier 		l *= p10[e-p-1];
1284e288d156SDavid du Colombier 	}else
1285e288d156SDavid du Colombier 		l = 0;
1286e288d156SDavid du Colombier 	if (*e == '\0' || strcmp(e, "s") == 0){
1287e288d156SDavid du Colombier 		ticks = 1000000000 * ticks + l;
1288e288d156SDavid du Colombier 	}else if (strcmp(e, "ms") == 0){
1289e288d156SDavid du Colombier 		ticks = 1000000 * ticks + l/1000;
1290e288d156SDavid du Colombier 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1291e288d156SDavid du Colombier 		ticks = 1000 * ticks + l/1000000;
1292e288d156SDavid du Colombier 	}else if (strcmp(e, "ns") != 0)
1293e288d156SDavid du Colombier 		return "unrecognized unit";
1294e288d156SDavid du Colombier 	*rt = ticks;
1295e288d156SDavid du Colombier 	return nil;
1296e288d156SDavid du Colombier }
1297e288d156SDavid du Colombier 
12987dd7cddfSDavid du Colombier void
procctlreq(Proc * p,char * va,int n)12997dd7cddfSDavid du Colombier procctlreq(Proc *p, char *va, int n)
13007dd7cddfSDavid du Colombier {
13017dd7cddfSDavid du Colombier 	Segment *s;
1302a6a9e072SDavid du Colombier 	int npc, pri;
13039a747e4fSDavid du Colombier 	Cmdbuf *cb;
13049a747e4fSDavid du Colombier 	Cmdtab *ct;
1305e288d156SDavid du Colombier 	vlong time;
1306e288d156SDavid du Colombier 	char *e;
13072cca75a1SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
13083e12c5d1SDavid du Colombier 
13099a747e4fSDavid du Colombier 	if(p->kp)	/* no ctl requests to kprocs */
13109a747e4fSDavid du Colombier 		error(Eperm);
13113e12c5d1SDavid du Colombier 
13129a747e4fSDavid du Colombier 	cb = parsecmd(va, n);
13139a747e4fSDavid du Colombier 	if(waserror()){
13149a747e4fSDavid du Colombier 		free(cb);
13159a747e4fSDavid du Colombier 		nexterror();
13169a747e4fSDavid du Colombier 	}
13179a747e4fSDavid du Colombier 
13189a747e4fSDavid du Colombier 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
13199a747e4fSDavid du Colombier 
13209a747e4fSDavid du Colombier 	switch(ct->index){
13219a747e4fSDavid du Colombier 	case CMclose:
13229a747e4fSDavid du Colombier 		procctlclosefiles(p, 0, atoi(cb->f[1]));
13239a747e4fSDavid du Colombier 		break;
13249a747e4fSDavid du Colombier 	case CMclosefiles:
13259a747e4fSDavid du Colombier 		procctlclosefiles(p, 1, 0);
13269a747e4fSDavid du Colombier 		break;
13279a747e4fSDavid du Colombier 	case CMhang:
13289a747e4fSDavid du Colombier 		p->hang = 1;
13299a747e4fSDavid du Colombier 		break;
13309a747e4fSDavid du Colombier 	case CMkill:
1331bd389b36SDavid du Colombier 		switch(p->state) {
1332bd389b36SDavid du Colombier 		case Broken:
1333bd389b36SDavid du Colombier 			unbreak(p);
1334bd389b36SDavid du Colombier 			break;
1335bd389b36SDavid du Colombier 		case Stopped:
1336bd389b36SDavid du Colombier 			p->procctl = Proc_exitme;
13372cca75a1SDavid du Colombier 			postnote(p, 0, "sys: killed", NExit);
13383e12c5d1SDavid du Colombier 			ready(p);
1339bd389b36SDavid du Colombier 			break;
1340bd389b36SDavid du Colombier 		default:
13413e12c5d1SDavid du Colombier 			p->procctl = Proc_exitme;
13422cca75a1SDavid du Colombier 			postnote(p, 0, "sys: killed", NExit);
13433e12c5d1SDavid du Colombier 		}
13449a747e4fSDavid du Colombier 		break;
13459a747e4fSDavid du Colombier 	case CMnohang:
1346219b2ee8SDavid du Colombier 		p->hang = 0;
13479a747e4fSDavid du Colombier 		break;
1348b7b24591SDavid du Colombier 	case CMnoswap:
1349b7b24591SDavid du Colombier 		p->noswap = 1;
1350b7b24591SDavid du Colombier 		break;
13519a747e4fSDavid du Colombier 	case CMpri:
1352a6a9e072SDavid du Colombier 		pri = atoi(cb->f[1]);
1353a6a9e072SDavid du Colombier 		if(pri > PriNormal && !iseve())
1354219b2ee8SDavid du Colombier 			error(Eperm);
1355a6a9e072SDavid du Colombier 		procpriority(p, pri, 0);
1356a6a9e072SDavid du Colombier 		break;
1357a6a9e072SDavid du Colombier 	case CMfixedpri:
135804b73bddSDavid du Colombier 		pri = atoi(cb->f[1]);
135904b73bddSDavid du Colombier 		if(pri > PriNormal && !iseve())
1360a6a9e072SDavid du Colombier 			error(Eperm);
136104b73bddSDavid du Colombier 		procpriority(p, pri, 1);
13629a747e4fSDavid du Colombier 		break;
13639a747e4fSDavid du Colombier 	case CMprivate:
13649a747e4fSDavid du Colombier 		p->privatemem = 1;
13659a747e4fSDavid du Colombier 		break;
13669a747e4fSDavid du Colombier 	case CMprofile:
13677dd7cddfSDavid du Colombier 		s = p->seg[TSEG];
13687dd7cddfSDavid du Colombier 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
13697dd7cddfSDavid du Colombier 			error(Ebadctl);
13707dd7cddfSDavid du Colombier 		if(s->profile != 0)
13717dd7cddfSDavid du Colombier 			free(s->profile);
13727dd7cddfSDavid du Colombier 		npc = (s->top-s->base)>>LRESPROF;
13737dd7cddfSDavid du Colombier 		s->profile = malloc(npc*sizeof(*s->profile));
13747dd7cddfSDavid du Colombier 		if(s->profile == 0)
13757dd7cddfSDavid du Colombier 			error(Enomem);
13769a747e4fSDavid du Colombier 		break;
13779a747e4fSDavid du Colombier 	case CMstart:
13789a747e4fSDavid du Colombier 		if(p->state != Stopped)
13793e12c5d1SDavid du Colombier 			error(Ebadctl);
13809a747e4fSDavid du Colombier 		ready(p);
13819a747e4fSDavid du Colombier 		break;
13829a747e4fSDavid du Colombier 	case CMstartstop:
13839a747e4fSDavid du Colombier 		if(p->state != Stopped)
13849a747e4fSDavid du Colombier 			error(Ebadctl);
13859a747e4fSDavid du Colombier 		p->procctl = Proc_traceme;
13869a747e4fSDavid du Colombier 		ready(p);
13879a747e4fSDavid du Colombier 		procstopwait(p, Proc_traceme);
13889a747e4fSDavid du Colombier 		break;
1389e288d156SDavid du Colombier 	case CMstartsyscall:
1390e288d156SDavid du Colombier 		if(p->state != Stopped)
1391e288d156SDavid du Colombier 			error(Ebadctl);
1392e288d156SDavid du Colombier 		p->procctl = Proc_tracesyscall;
1393e288d156SDavid du Colombier 		ready(p);
1394e288d156SDavid du Colombier 		procstopwait(p, Proc_tracesyscall);
1395e288d156SDavid du Colombier 		break;
13969a747e4fSDavid du Colombier 	case CMstop:
13979a747e4fSDavid du Colombier 		procstopwait(p, Proc_stopme);
13989a747e4fSDavid du Colombier 		break;
13999a747e4fSDavid du Colombier 	case CMwaitstop:
14009a747e4fSDavid du Colombier 		procstopwait(p, 0);
14019a747e4fSDavid du Colombier 		break;
14029a747e4fSDavid du Colombier 	case CMwired:
14039a747e4fSDavid du Colombier 		procwired(p, atoi(cb->f[1]));
14049a747e4fSDavid du Colombier 		break;
1405e288d156SDavid du Colombier 	case CMtrace:
1406179dd269SDavid du Colombier 		switch(cb->nf){
1407179dd269SDavid du Colombier 		case 1:
1408220e960cSDavid du Colombier 			p->trace ^= 1;
1409e288d156SDavid du Colombier 			break;
1410179dd269SDavid du Colombier 		case 2:
141125910e17SDavid du Colombier 			p->trace = (atoi(cb->f[1]) != 0);
1412179dd269SDavid du Colombier 			break;
1413179dd269SDavid du Colombier 		default:
1414179dd269SDavid du Colombier 			error("args");
1415179dd269SDavid du Colombier 		}
1416179dd269SDavid du Colombier 		break;
1417e288d156SDavid du Colombier 	/* real time */
1418e288d156SDavid du Colombier 	case CMperiod:
1419e288d156SDavid du Colombier 		if(p->edf == nil)
1420e288d156SDavid du Colombier 			edfinit(p);
14212cca75a1SDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1422e288d156SDavid du Colombier 			error(e);
1423e288d156SDavid du Colombier 		edfstop(p);
14242cca75a1SDavid du Colombier 		p->edf->T = time/1000;	/* Edf times are in µs */
1425e288d156SDavid du Colombier 		break;
1426e288d156SDavid du Colombier 	case CMdeadline:
1427e288d156SDavid du Colombier 		if(p->edf == nil)
1428e288d156SDavid du Colombier 			edfinit(p);
1429e288d156SDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))
1430e288d156SDavid du Colombier 			error(e);
1431e288d156SDavid du Colombier 		edfstop(p);
14322cca75a1SDavid du Colombier 		p->edf->D = time/1000;
1433e288d156SDavid du Colombier 		break;
1434e288d156SDavid du Colombier 	case CMcost:
1435e288d156SDavid du Colombier 		if(p->edf == nil)
1436e288d156SDavid du Colombier 			edfinit(p);
1437e288d156SDavid du Colombier 		if(e=parsetime(&time, cb->f[1]))
1438e288d156SDavid du Colombier 			error(e);
1439e288d156SDavid du Colombier 		edfstop(p);
14402cca75a1SDavid du Colombier 		p->edf->C = time/1000;
1441e288d156SDavid du Colombier 		break;
1442e288d156SDavid du Colombier 	case CMsporadic:
1443e288d156SDavid du Colombier 		if(p->edf == nil)
1444e288d156SDavid du Colombier 			edfinit(p);
1445e288d156SDavid du Colombier 		p->edf->flags |= Sporadic;
1446e288d156SDavid du Colombier 		break;
1447e288d156SDavid du Colombier 	case CMdeadlinenotes:
1448e288d156SDavid du Colombier 		if(p->edf == nil)
1449e288d156SDavid du Colombier 			edfinit(p);
1450e288d156SDavid du Colombier 		p->edf->flags |= Sendnotes;
1451e288d156SDavid du Colombier 		break;
1452e288d156SDavid du Colombier 	case CMadmit:
1453e288d156SDavid du Colombier 		if(p->edf == 0)
1454e288d156SDavid du Colombier 			error("edf params");
1455e288d156SDavid du Colombier 		if(e = edfadmit(p))
1456e288d156SDavid du Colombier 			error(e);
1457e288d156SDavid du Colombier 		break;
1458179dd269SDavid du Colombier 	case CMextra:
1459179dd269SDavid du Colombier 		if(p->edf == nil)
1460179dd269SDavid du Colombier 			edfinit(p);
1461179dd269SDavid du Colombier 		p->edf->flags |= Extratime;
1462179dd269SDavid du Colombier 		break;
1463e288d156SDavid du Colombier 	case CMexpel:
1464e288d156SDavid du Colombier 		if(p->edf)
1465e288d156SDavid du Colombier 			edfstop(p);
1466e288d156SDavid du Colombier 		break;
14672cca75a1SDavid du Colombier 	case CMevent:
14682cca75a1SDavid du Colombier 		pt = proctrace;
14692cca75a1SDavid du Colombier 		if(up->trace && pt)
14702cca75a1SDavid du Colombier 			pt(up, SUser, 0);
14712cca75a1SDavid du Colombier 		break;
14729a747e4fSDavid du Colombier 	}
14739a747e4fSDavid du Colombier 
14749a747e4fSDavid du Colombier 	poperror();
14759a747e4fSDavid du Colombier 	free(cb);
14763e12c5d1SDavid du Colombier }
14773e12c5d1SDavid du Colombier 
14783e12c5d1SDavid du Colombier int
procstopped(void * a)14793e12c5d1SDavid du Colombier procstopped(void *a)
14803e12c5d1SDavid du Colombier {
14813e12c5d1SDavid du Colombier 	Proc *p = a;
14823e12c5d1SDavid du Colombier 	return p->state == Stopped;
14833e12c5d1SDavid du Colombier }
14843e12c5d1SDavid du Colombier 
14853e12c5d1SDavid du Colombier int
procctlmemio(Proc * p,ulong offset,int n,void * va,int read)14863e12c5d1SDavid du Colombier procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
14873e12c5d1SDavid du Colombier {
14883e12c5d1SDavid du Colombier 	KMap *k;
14893e12c5d1SDavid du Colombier 	Pte *pte;
14903e12c5d1SDavid du Colombier 	Page *pg;
14913e12c5d1SDavid du Colombier 	Segment *s;
14923e12c5d1SDavid du Colombier 	ulong soff, l;
14933e12c5d1SDavid du Colombier 	char *a = va, *b;
14943e12c5d1SDavid du Colombier 
14953e12c5d1SDavid du Colombier 	for(;;) {
14963e12c5d1SDavid du Colombier 		s = seg(p, offset, 1);
14973e12c5d1SDavid du Colombier 		if(s == 0)
14983e12c5d1SDavid du Colombier 			error(Ebadarg);
14993e12c5d1SDavid du Colombier 
15003e12c5d1SDavid du Colombier 		if(offset+n >= s->top)
15013e12c5d1SDavid du Colombier 			n = s->top-offset;
15023e12c5d1SDavid du Colombier 
15037dd7cddfSDavid du Colombier 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
15043e12c5d1SDavid du Colombier 			s = txt2data(p, s);
15053e12c5d1SDavid du Colombier 
15063e12c5d1SDavid du Colombier 		s->steal++;
15073e12c5d1SDavid du Colombier 		soff = offset-s->base;
15083e12c5d1SDavid du Colombier 		if(waserror()) {
15093e12c5d1SDavid du Colombier 			s->steal--;
15103e12c5d1SDavid du Colombier 			nexterror();
15113e12c5d1SDavid du Colombier 		}
15123e12c5d1SDavid du Colombier 		if(fixfault(s, offset, read, 0) == 0)
15133e12c5d1SDavid du Colombier 			break;
15143e12c5d1SDavid du Colombier 		poperror();
15153e12c5d1SDavid du Colombier 		s->steal--;
15163e12c5d1SDavid du Colombier 	}
15173e12c5d1SDavid du Colombier 	poperror();
15183e12c5d1SDavid du Colombier 	pte = s->map[soff/PTEMAPMEM];
15193e12c5d1SDavid du Colombier 	if(pte == 0)
15203e12c5d1SDavid du Colombier 		panic("procctlmemio");
15213e12c5d1SDavid du Colombier 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
15223e12c5d1SDavid du Colombier 	if(pagedout(pg))
15233e12c5d1SDavid du Colombier 		panic("procctlmemio1");
15243e12c5d1SDavid du Colombier 
15253e12c5d1SDavid du Colombier 	l = BY2PG - (offset&(BY2PG-1));
15263e12c5d1SDavid du Colombier 	if(n > l)
15273e12c5d1SDavid du Colombier 		n = l;
15283e12c5d1SDavid du Colombier 
15293e12c5d1SDavid du Colombier 	k = kmap(pg);
15307dd7cddfSDavid du Colombier 	if(waserror()) {
15317dd7cddfSDavid du Colombier 		s->steal--;
15323e12c5d1SDavid du Colombier 		kunmap(k);
15337dd7cddfSDavid du Colombier 		nexterror();
15347dd7cddfSDavid du Colombier 	}
15357dd7cddfSDavid du Colombier 	b = (char*)VA(k);
15367dd7cddfSDavid du Colombier 	b += offset&(BY2PG-1);
15377dd7cddfSDavid du Colombier 	if(read == 1)
15387dd7cddfSDavid du Colombier 		memmove(a, b, n);	/* This can fault */
15397dd7cddfSDavid du Colombier 	else
15407dd7cddfSDavid du Colombier 		memmove(b, a, n);
15417dd7cddfSDavid du Colombier 	kunmap(k);
15427dd7cddfSDavid du Colombier 	poperror();
15437dd7cddfSDavid du Colombier 
15447dd7cddfSDavid du Colombier 	/* Ensure the process sees text page changes */
15457dd7cddfSDavid du Colombier 	if(s->flushme)
15467dd7cddfSDavid du Colombier 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
15473e12c5d1SDavid du Colombier 
15483e12c5d1SDavid du Colombier 	s->steal--;
15493e12c5d1SDavid du Colombier 
15503e12c5d1SDavid du Colombier 	if(read == 0)
15513e12c5d1SDavid du Colombier 		p->newtlb = 1;
15523e12c5d1SDavid du Colombier 
15533e12c5d1SDavid du Colombier 	return n;
15543e12c5d1SDavid du Colombier }
15553e12c5d1SDavid du Colombier 
15563e12c5d1SDavid du Colombier Segment*
txt2data(Proc * p,Segment * s)15573e12c5d1SDavid du Colombier txt2data(Proc *p, Segment *s)
15583e12c5d1SDavid du Colombier {
15593e12c5d1SDavid du Colombier 	int i;
15603e12c5d1SDavid du Colombier 	Segment *ps;
15613e12c5d1SDavid du Colombier 
15623e12c5d1SDavid du Colombier 	ps = newseg(SG_DATA, s->base, s->size);
15633e12c5d1SDavid du Colombier 	ps->image = s->image;
15643e12c5d1SDavid du Colombier 	incref(ps->image);
15653e12c5d1SDavid du Colombier 	ps->fstart = s->fstart;
15663e12c5d1SDavid du Colombier 	ps->flen = s->flen;
15673e12c5d1SDavid du Colombier 	ps->flushme = 1;
15683e12c5d1SDavid du Colombier 
15697dd7cddfSDavid du Colombier 	qlock(&p->seglock);
15703e12c5d1SDavid du Colombier 	for(i = 0; i < NSEG; i++)
15713e12c5d1SDavid du Colombier 		if(p->seg[i] == s)
15723e12c5d1SDavid du Colombier 			break;
15737dbf685cSDavid du Colombier 	if(i == NSEG)
15743e12c5d1SDavid du Colombier 		panic("segment gone");
15753e12c5d1SDavid du Colombier 
15763e12c5d1SDavid du Colombier 	qunlock(&s->lk);
15773e12c5d1SDavid du Colombier 	putseg(s);
15783e12c5d1SDavid du Colombier 	qlock(&ps->lk);
15793e12c5d1SDavid du Colombier 	p->seg[i] = ps;
15807dd7cddfSDavid du Colombier 	qunlock(&p->seglock);
15813e12c5d1SDavid du Colombier 
15823e12c5d1SDavid du Colombier 	return ps;
15833e12c5d1SDavid du Colombier }
1584bd389b36SDavid du Colombier 
1585bd389b36SDavid du Colombier Segment*
data2txt(Segment * s)1586bd389b36SDavid du Colombier data2txt(Segment *s)
1587bd389b36SDavid du Colombier {
1588bd389b36SDavid du Colombier 	Segment *ps;
1589bd389b36SDavid du Colombier 
1590bd389b36SDavid du Colombier 	ps = newseg(SG_TEXT, s->base, s->size);
1591bd389b36SDavid du Colombier 	ps->image = s->image;
1592bd389b36SDavid du Colombier 	incref(ps->image);
1593bd389b36SDavid du Colombier 	ps->fstart = s->fstart;
1594bd389b36SDavid du Colombier 	ps->flen = s->flen;
1595bd389b36SDavid du Colombier 	ps->flushme = 1;
1596bd389b36SDavid du Colombier 
1597bd389b36SDavid du Colombier 	return ps;
1598bd389b36SDavid du Colombier }
1599