xref: /plan9-contrib/sys/src/9/port/devproc.c (revision b39189fd423aed869c5cf5189bc504918cff969b)
1 #include	"u.h"
2 #include	<trace.h>
3 #include	"tos.h"
4 #include	"../port/lib.h"
5 #include	"mem.h"
6 #include	"dat.h"
7 #include	"fns.h"
8 #include	"../port/error.h"
9 #include	"ureg.h"
10 #include	"edf.h"
11 
12 enum
13 {
14 	Qdir,
15 	Qtrace,
16 	Qargs,
17 	Qctl,
18 	Qfd,
19 	Qfpregs,
20 	Qkregs,
21 	Qmem,
22 	Qnote,
23 	Qnoteid,
24 	Qnotepg,
25 	Qns,
26 	Qproc,
27 	Qregs,
28 	Qsegment,
29 	Qstatus,
30 	Qtext,
31 	Qwait,
32 	Qprofile,
33 };
34 
35 enum
36 {
37 	CMclose,
38 	CMclosefiles,
39 	CMfixedpri,
40 	CMhang,
41 	CMkill,
42 	CMnohang,
43 	CMnoswap,
44 	CMpri,
45 	CMprivate,
46 	CMprofile,
47 	CMstart,
48 	CMstartstop,
49 	CMstartsyscall,
50 	CMstop,
51 	CMwaitstop,
52 	CMwired,
53 	CMtrace,
54 	/* real time */
55 	CMperiod,
56 	CMdeadline,
57 	CMcost,
58 	CMsporadic,
59 	CMdeadlinenotes,
60 	CMadmit,
61 	CMextra,
62 	CMexpel,
63 	CMevent,
64 };
65 
66 enum{
67 	Nevents = 0x4000,
68 	Emask = Nevents - 1,
69 };
70 
71 #define	STATSIZE	(2*KNAMELEN+12+9*12)
72 /*
73  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
74  * particularly on shared servers.
75  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
76  */
77 Dirtab procdir[] =
78 {
79 	"args",		{Qargs},	0,			0660,
80 	"ctl",		{Qctl},		0,			0000,
81 	"fd",		{Qfd},		0,			0444,
82 	"fpregs",	{Qfpregs},	sizeof(FPsave),		0000,
83 	"kregs",	{Qkregs},	sizeof(Ureg),		0400,
84 	"mem",		{Qmem},		0,			0000,
85 	"note",		{Qnote},	0,			0000,
86 	"noteid",	{Qnoteid},	0,			0664,
87 	"notepg",	{Qnotepg},	0,			0000,
88 	"ns",		{Qns},		0,			0444,
89 	"proc",		{Qproc},	0,			0400,
90 	"regs",		{Qregs},	sizeof(Ureg),		0000,
91 	"segment",	{Qsegment},	0,			0444,
92 	"status",	{Qstatus},	STATSIZE,		0444,
93 	"text",		{Qtext},	0,			0000,
94 	"wait",		{Qwait},	0,			0400,
95 	"profile",	{Qprofile},	0,			0400,
96 };
97 
98 static
99 Cmdtab proccmd[] = {
100 	CMclose,		"close",		2,
101 	CMclosefiles,		"closefiles",		1,
102 	CMfixedpri,		"fixedpri",		2,
103 	CMhang,			"hang",			1,
104 	CMnohang,		"nohang",		1,
105 	CMnoswap,		"noswap",		1,
106 	CMkill,			"kill",			1,
107 	CMpri,			"pri",			2,
108 	CMprivate,		"private",		1,
109 	CMprofile,		"profile",		1,
110 	CMstart,		"start",		1,
111 	CMstartstop,		"startstop",		1,
112 	CMstartsyscall,		"startsyscall",		1,
113 	CMstop,			"stop",			1,
114 	CMwaitstop,		"waitstop",		1,
115 	CMwired,		"wired",		2,
116 	CMtrace,		"trace",		0,
117 	CMperiod,		"period",		2,
118 	CMdeadline,		"deadline",		2,
119 	CMcost,			"cost",			2,
120 	CMsporadic,		"sporadic",		1,
121 	CMdeadlinenotes,	"deadlinenotes",	1,
122 	CMadmit,		"admit",		1,
123 	CMextra,		"extra",		1,
124 	CMexpel,		"expel",		1,
125 	CMevent,		"event",		1,
126 };
127 
128 /* Segment type from portdat.h */
129 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
130 
131 /*
132  * Qids are, in path:
133  *	 4 bits of file type (qids above)
134  *	23 bits of process slot number + 1
135  *	     in vers,
136  *	32 bits of pid, for consistency checking
137  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
138  */
139 #define	QSHIFT	5	/* location in qid of proc slot # */
140 
141 #define	QID(q)		((((ulong)(q).path)&0x0000001F)>>0)
142 #define	SLOT(q)		(((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
143 #define	PID(q)		((q).vers)
144 #define	NOTEID(q)	((q).vers)
145 
146 void	procctlreq(Proc*, char*, int);
147 int	procctlmemio(Proc*, ulong, int, void*, int);
148 Chan*	proctext(Chan*, Proc*);
149 Segment* txt2data(Proc*, Segment*);
150 int	procstopped(void*);
151 void	mntscan(Mntwalk*, Proc*);
152 
153 static Traceevent *tevents;
154 static Lock tlock;
155 static int topens;
156 static int tproduced, tconsumed;
157 void (*proctrace)(Proc*, int, vlong);
158 
159 extern int unfair;
160 
161 static void
162 profclock(Ureg *ur, Timer *)
163 {
164 	Tos *tos;
165 
166 	if(up == 0 || up->state != Running)
167 		return;
168 
169 	/* user profiling clock */
170 	if(userureg(ur)){
171 		tos = (Tos*)(USTKTOP-sizeof(Tos));
172 		tos->clock += TK2MS(1);
173 		segclock(ur->pc);
174 	}
175 }
176 
177 static int
178 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
179 {
180 	Qid qid;
181 	Proc *p;
182 	char *ename;
183 	Segment *q;
184 	ulong pid, path, perm, len;
185 
186 	if(s == DEVDOTDOT){
187 		mkqid(&qid, Qdir, 0, QTDIR);
188 		devdir(c, qid, "#p", 0, eve, 0555, dp);
189 		return 1;
190 	}
191 
192 	if(c->qid.path == Qdir){
193 		if(s == 0){
194 			strcpy(up->genbuf, "trace");
195 			mkqid(&qid, Qtrace, -1, QTFILE);
196 			devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
197 			return 1;
198 		}
199 
200 		if(name != nil){
201 			/* ignore s and use name to find pid */
202 			pid = strtol(name, &ename, 10);
203 			if(pid==0 || ename[0]!='\0')
204 				return -1;
205 			s = procindex(pid);
206 			if(s < 0)
207 				return -1;
208 		}
209 		else if(--s >= conf.nproc)
210 			return -1;
211 
212 		p = proctab(s);
213 		pid = p->pid;
214 		if(pid == 0)
215 			return 0;
216 		sprint(up->genbuf, "%lud", pid);
217 		/*
218 		 * String comparison is done in devwalk so name must match its formatted pid
219 		*/
220 		if(name != nil && strcmp(name, up->genbuf) != 0)
221 			return -1;
222 		mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
223 		devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
224 		return 1;
225 	}
226 	if(c->qid.path == Qtrace){
227 		strcpy(up->genbuf, "trace");
228 		mkqid(&qid, Qtrace, -1, QTFILE);
229 		devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
230 		return 1;
231 	}
232 	if(s >= nelem(procdir))
233 		return -1;
234 	if(tab)
235 		panic("procgen");
236 
237 	tab = &procdir[s];
238 	path = c->qid.path&~(((1<<QSHIFT)-1));	/* slot component */
239 
240 	p = proctab(SLOT(c->qid));
241 	perm = tab->perm;
242 	if(perm == 0)
243 		perm = p->procmode;
244 	else	/* just copy read bits */
245 		perm |= p->procmode & 0444;
246 
247 	len = tab->length;
248 	switch(QID(c->qid)) {
249 	case Qwait:
250 		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
251 		break;
252 	case Qprofile:
253 		q = p->seg[TSEG];
254 		if(q && q->profile) {
255 			len = (q->top-q->base)>>LRESPROF;
256 			len *= sizeof(*q->profile);
257 		}
258 		break;
259 	}
260 
261 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
262 	devdir(c, qid, tab->name, len, p->user, perm, dp);
263 	return 1;
264 }
265 
266 static void
267 _proctrace(Proc* p, Tevent etype, vlong ts)
268 {
269 	Traceevent *te;
270 
271 	if (p->trace == 0 || topens == 0 ||
272 		tproduced - tconsumed >= Nevents)
273 		return;
274 
275 	te = &tevents[tproduced&Emask];
276 	te->pid = p->pid;
277 	te->etype = etype;
278 	if (ts == 0)
279 		te->time = todget(nil);
280 	else
281 		te->time = ts;
282 	tproduced++;
283 }
284 
285 static void
286 procinit(void)
287 {
288 	if(conf.nproc >= (1<<(16-QSHIFT))-1)
289 		print("warning: too many procs for devproc\n");
290 	addclock0link((void (*)(void))profclock, 113);	/* Relative prime to HZ */
291 }
292 
293 static Chan*
294 procattach(char *spec)
295 {
296 	return devattach('p', spec);
297 }
298 
299 static Walkqid*
300 procwalk(Chan *c, Chan *nc, char **name, int nname)
301 {
302 	return devwalk(c, nc, name, nname, 0, 0, procgen);
303 }
304 
305 static int
306 procstat(Chan *c, uchar *db, int n)
307 {
308 	return devstat(c, db, n, 0, 0, procgen);
309 }
310 
311 /*
312  *  none can't read or write state on other
313  *  processes.  This is to contain access of
314  *  servers running as none should they be
315  *  subverted by, for example, a stack attack.
316  */
317 static void
318 nonone(Proc *p)
319 {
320 	if(p == up)
321 		return;
322 	if(strcmp(up->user, "none") != 0)
323 		return;
324 	if(iseve())
325 		return;
326 	error(Eperm);
327 }
328 
329 static Chan*
330 procopen(Chan *c, int omode)
331 {
332 	Proc *p;
333 	Pgrp *pg;
334 	Chan *tc;
335 	int pid;
336 
337 	if(c->qid.type & QTDIR)
338 		return devopen(c, omode, 0, 0, procgen);
339 
340 	if(QID(c->qid) == Qtrace){
341 		if (omode != OREAD)
342 			error(Eperm);
343 		lock(&tlock);
344 		if (waserror()){
345 			unlock(&tlock);
346 			nexterror();
347 		}
348 		if (topens > 0)
349 			error("already open");
350 		topens++;
351 		if (tevents == nil){
352 			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
353 			if(tevents == nil)
354 				error(Enomem);
355 			tproduced = tconsumed = 0;
356 		}
357 		proctrace = _proctrace;
358 		unlock(&tlock);
359 		poperror();
360 
361 		c->mode = openmode(omode);
362 		c->flag |= COPEN;
363 		c->offset = 0;
364 		return c;
365 	}
366 
367 	p = proctab(SLOT(c->qid));
368 	qlock(&p->debug);
369 	if(waserror()){
370 		qunlock(&p->debug);
371 		nexterror();
372 	}
373 	pid = PID(c->qid);
374 	if(p->pid != pid)
375 		error(Eprocdied);
376 
377 	omode = openmode(omode);
378 
379 	switch(QID(c->qid)){
380 	case Qtext:
381 		if(omode != OREAD)
382 			error(Eperm);
383 		tc = proctext(c, p);
384 		tc->offset = 0;
385 		qunlock(&p->debug);
386 		poperror();
387 		return tc;
388 
389 	case Qproc:
390 	case Qkregs:
391 	case Qsegment:
392 	case Qprofile:
393 	case Qfd:
394 		if(omode != OREAD)
395 			error(Eperm);
396 		break;
397 
398 	case Qnote:
399 		if(p->privatemem)
400 			error(Eperm);
401 		break;
402 
403 	case Qmem:
404 	case Qctl:
405 		if(p->privatemem)
406 			error(Eperm);
407 		nonone(p);
408 		break;
409 
410 	case Qargs:
411 	case Qnoteid:
412 	case Qstatus:
413 	case Qwait:
414 	case Qregs:
415 	case Qfpregs:
416 		nonone(p);
417 		break;
418 
419 	case Qns:
420 		if(omode != OREAD)
421 			error(Eperm);
422 		c->aux = malloc(sizeof(Mntwalk));
423 		break;
424 
425 	case Qnotepg:
426 		nonone(p);
427 		pg = p->pgrp;
428 		if(pg == nil)
429 			error(Eprocdied);
430 		if(omode!=OWRITE || pg->pgrpid == 1)
431 			error(Eperm);
432 		c->pgrpid.path = pg->pgrpid+1;
433 		c->pgrpid.vers = p->noteid;
434 		break;
435 
436 	default:
437 		pprint("procopen %#lux\n", QID(c->qid));
438 		error(Egreg);
439 	}
440 
441 	/* Affix pid to qid */
442 	if(p->state != Dead)
443 		c->qid.vers = p->pid;
444 
445 	/* make sure the process slot didn't get reallocated while we were playing */
446 	coherence();
447 	if(p->pid != pid)
448 		error(Eprocdied);
449 
450 	tc = devopen(c, omode, 0, 0, procgen);
451 	qunlock(&p->debug);
452 	poperror();
453 
454 	return tc;
455 }
456 
457 static int
458 procwstat(Chan *c, uchar *db, int n)
459 {
460 	Proc *p;
461 	Dir *d;
462 
463 	if(c->qid.type&QTDIR)
464 		error(Eperm);
465 
466 	if(QID(c->qid) == Qtrace)
467 		return devwstat(c, db, n);
468 
469 	p = proctab(SLOT(c->qid));
470 	nonone(p);
471 	d = nil;
472 	if(waserror()){
473 		free(d);
474 		qunlock(&p->debug);
475 		nexterror();
476 	}
477 	qlock(&p->debug);
478 
479 	if(p->pid != PID(c->qid))
480 		error(Eprocdied);
481 
482 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
483 		error(Eperm);
484 
485 	d = smalloc(sizeof(Dir)+n);
486 	n = convM2D(db, n, &d[0], (char*)&d[1]);
487 	if(n == 0)
488 		error(Eshortstat);
489 	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
490 		if(strcmp(up->user, eve) != 0)
491 			error(Eperm);
492 		else
493 			kstrdup(&p->user, d->uid);
494 	}
495 	if(d->mode != ~0UL)
496 		p->procmode = d->mode&0777;
497 
498 	poperror();
499 	free(d);
500 	qunlock(&p->debug);
501 	return n;
502 }
503 
504 
505 static long
506 procoffset(long offset, char *va, int *np)
507 {
508 	if(offset > 0) {
509 		offset -= *np;
510 		if(offset < 0) {
511 			memmove(va, va+*np+offset, -offset);
512 			*np = -offset;
513 		}
514 		else
515 			*np = 0;
516 	}
517 	return offset;
518 }
519 
520 static int
521 procqidwidth(Chan *c)
522 {
523 	char buf[32];
524 
525 	return sprint(buf, "%lud", c->qid.vers);
526 }
527 
528 int
529 procfdprint(Chan *c, int fd, int w, char *s, int ns)
530 {
531 	int n;
532 
533 	if(w == 0)
534 		w = procqidwidth(c);
535 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
536 		fd,
537 		&"r w rw"[(c->mode&3)<<1],
538 		devtab[c->type]->dc, c->dev,
539 		c->qid.path, w, c->qid.vers, c->qid.type,
540 		c->iounit, c->offset, c->path->s);
541 	return n;
542 }
543 
544 static int
545 procfds(Proc *p, char *va, int count, long offset)
546 {
547 	Fgrp *f;
548 	Chan *c;
549 	char buf[256];
550 	int n, i, w, ww;
551 	char *a;
552 
553 	/* print to buf to avoid holding fgrp lock while writing to user space */
554 	if(count > sizeof buf)
555 		count = sizeof buf;
556 	a = buf;
557 
558 	qlock(&p->debug);
559 	f = p->fgrp;
560 	if(f == nil){
561 		qunlock(&p->debug);
562 		return 0;
563 	}
564 	lock(f);
565 	if(waserror()){
566 		unlock(f);
567 		qunlock(&p->debug);
568 		nexterror();
569 	}
570 
571 	n = readstr(0, a, count, p->dot->path->s);
572 	n += snprint(a+n, count-n, "\n");
573 	offset = procoffset(offset, a, &n);
574 	/* compute width of qid.path */
575 	w = 0;
576 	for(i = 0; i <= f->maxfd; i++) {
577 		c = f->fd[i];
578 		if(c == nil)
579 			continue;
580 		ww = procqidwidth(c);
581 		if(ww > w)
582 			w = ww;
583 	}
584 	for(i = 0; i <= f->maxfd; i++) {
585 		c = f->fd[i];
586 		if(c == nil)
587 			continue;
588 		n += procfdprint(c, i, w, a+n, count-n);
589 		offset = procoffset(offset, a, &n);
590 	}
591 	unlock(f);
592 	qunlock(&p->debug);
593 	poperror();
594 
595 	/* copy result to user space, now that locks are released */
596 	memmove(va, buf, n);
597 
598 	return n;
599 }
600 
601 static void
602 procclose(Chan * c)
603 {
604 	if(QID(c->qid) == Qtrace){
605 		lock(&tlock);
606 		if(topens > 0)
607 			topens--;
608 		if(topens == 0)
609 			proctrace = nil;
610 		unlock(&tlock);
611 	}
612 	if(QID(c->qid) == Qns && c->aux != 0)
613 		free(c->aux);
614 }
615 
616 static void
617 int2flag(int flag, char *s)
618 {
619 	if(flag == 0){
620 		*s = '\0';
621 		return;
622 	}
623 	*s++ = '-';
624 	if(flag & MAFTER)
625 		*s++ = 'a';
626 	if(flag & MBEFORE)
627 		*s++ = 'b';
628 	if(flag & MCREATE)
629 		*s++ = 'c';
630 	if(flag & MCACHE)
631 		*s++ = 'C';
632 	*s = '\0';
633 }
634 
635 static int
636 procargs(Proc *p, char *buf, int nbuf)
637 {
638 	int j, k, m;
639 	char *a;
640 	int n;
641 
642 	a = p->args;
643 	if(p->setargs){
644 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
645 		return strlen(buf);
646 	}
647 	n = p->nargs;
648 	for(j = 0; j < nbuf - 1; j += m){
649 		if(n <= 0)
650 			break;
651 		if(j != 0)
652 			buf[j++] = ' ';
653 		m = snprint(buf+j, nbuf-j, "%q",  a);
654 		k = strlen(a) + 1;
655 		a += k;
656 		n -= k;
657 	}
658 	return j;
659 }
660 
661 static int
662 eventsavailable(void *)
663 {
664 	return tproduced > tconsumed;
665 }
666 
667 static long
668 procread(Chan *c, void *va, long n, vlong off)
669 {
670 	/* NSEG*32 was too small for worst cases */
671 	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
672 	int i, j, m, navail, ne, pid, rsize;
673 	long l;
674 	uchar *rptr;
675 	ulong offset;
676 	Confmem *cm;
677 	Mntwalk *mw;
678 	Proc *p;
679 	Segment *sg, *s;
680 	Ureg kur;
681 	Waitq *wq;
682 
683 	a = va;
684 	offset = off;
685 
686 	if(c->qid.type & QTDIR)
687 		return devdirread(c, a, n, 0, 0, procgen);
688 
689 	if(QID(c->qid) == Qtrace){
690 		if(!eventsavailable(nil))
691 			return 0;
692 
693 		rptr = (uchar*)va;
694 		navail = tproduced - tconsumed;
695 		if(navail > n / sizeof(Traceevent))
696 			navail = n / sizeof(Traceevent);
697 		while(navail > 0) {
698 			ne = ((tconsumed & Emask) + navail > Nevents)?
699 					Nevents - (tconsumed & Emask): navail;
700 			memmove(rptr, &tevents[tconsumed & Emask],
701 					ne * sizeof(Traceevent));
702 
703 			tconsumed += ne;
704 			rptr += ne * sizeof(Traceevent);
705 			navail -= ne;
706 		}
707 		return rptr - (uchar*)va;
708 	}
709 
710 	p = proctab(SLOT(c->qid));
711 	if(p->pid != PID(c->qid))
712 		error(Eprocdied);
713 
714 	switch(QID(c->qid)){
715 	case Qargs:
716 		qlock(&p->debug);
717 		j = procargs(p, up->genbuf, sizeof up->genbuf);
718 		qunlock(&p->debug);
719 		if(offset >= j)
720 			return 0;
721 		if(offset+n > j)
722 			n = j-offset;
723 		memmove(a, &up->genbuf[offset], n);
724 		return n;
725 
726 	case Qmem:
727 		if(offset < KZERO)
728 			return procctlmemio(p, offset, n, va, 1);
729 
730 		if(!iseve())
731 			error(Eperm);
732 
733 		/* validate kernel addresses */
734 		if(offset < (ulong)end) {
735 			if(offset+n > (ulong)end)
736 				n = (ulong)end - offset;
737 			memmove(a, (char*)offset, n);
738 			return n;
739 		}
740 		for(i=0; i<nelem(conf.mem); i++){
741 			cm = &conf.mem[i];
742 			/* klimit-1 because klimit might be zero! */
743 			if(cm->kbase <= offset && offset <= cm->klimit-1){
744 				if(offset+n >= cm->klimit-1)
745 					n = cm->klimit - offset;
746 				memmove(a, (char*)offset, n);
747 				return n;
748 			}
749 		}
750 		error(Ebadarg);
751 
752 	case Qprofile:
753 		s = p->seg[TSEG];
754 		if(s == 0 || s->profile == 0)
755 			error("profile is off");
756 		i = (s->top-s->base)>>LRESPROF;
757 		i *= sizeof(*s->profile);
758 		if(offset >= i)
759 			return 0;
760 		if(offset+n > i)
761 			n = i - offset;
762 		memmove(a, ((char*)s->profile)+offset, n);
763 		return n;
764 
765 	case Qnote:
766 		qlock(&p->debug);
767 		if(waserror()){
768 			qunlock(&p->debug);
769 			nexterror();
770 		}
771 		if(p->pid != PID(c->qid))
772 			error(Eprocdied);
773 		if(n < 1)	/* must accept at least the '\0' */
774 			error(Etoosmall);
775 		if(p->nnote == 0)
776 			n = 0;
777 		else {
778 			m = strlen(p->note[0].msg) + 1;
779 			if(m > n)
780 				m = n;
781 			memmove(va, p->note[0].msg, m);
782 			((char*)va)[m-1] = '\0';
783 			p->nnote--;
784 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
785 			n = m;
786 		}
787 		if(p->nnote == 0)
788 			p->notepending = 0;
789 		poperror();
790 		qunlock(&p->debug);
791 		return n;
792 
793 	case Qproc:
794 		if(offset >= sizeof(Proc))
795 			return 0;
796 		if(offset+n > sizeof(Proc))
797 			n = sizeof(Proc) - offset;
798 		memmove(a, ((char*)p)+offset, n);
799 		return n;
800 
801 	case Qregs:
802 		rptr = (uchar*)p->dbgreg;
803 		rsize = sizeof(Ureg);
804 		goto regread;
805 
806 	case Qkregs:
807 		memset(&kur, 0, sizeof(Ureg));
808 		setkernur(&kur, p);
809 		rptr = (uchar*)&kur;
810 		rsize = sizeof(Ureg);
811 		goto regread;
812 
813 	case Qfpregs:
814 		rptr = (uchar*)&p->fpsave;
815 		rsize = sizeof(FPsave);
816 	regread:
817 		if(rptr == 0)
818 			error(Enoreg);
819 		if(offset >= rsize)
820 			return 0;
821 		if(offset+n > rsize)
822 			n = rsize - offset;
823 		memmove(a, rptr+offset, n);
824 		return n;
825 
826 	case Qstatus:
827 		if(offset >= STATSIZE)
828 			return 0;
829 		if(offset+n > STATSIZE)
830 			n = STATSIZE - offset;
831 
832 		sps = p->psstate;
833 		if(sps == 0)
834 			sps = statename[p->state];
835 		memset(statbuf, ' ', sizeof statbuf);
836 		memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
837 		memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
838 		memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
839 		j = 2*KNAMELEN + 12;
840 
841 		for(i = 0; i < 6; i++) {
842 			l = p->time[i];
843 			if(i == TReal)
844 				l = MACHP(0)->ticks - l;
845 			l = TK2MS(l);
846 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
847 		}
848 		/* ignore stack, which is mostly non-existent */
849 		l = 0;
850 		for(i=1; i<NSEG; i++){
851 			s = p->seg[i];
852 			if(s)
853 				l += s->top - s->base;
854 		}
855 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
856 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
857 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
858 		memmove(a, statbuf+offset, n);
859 		return n;
860 
861 	case Qsegment:
862 		j = 0;
863 		for(i = 0; i < NSEG; i++) {
864 			sg = p->seg[i];
865 			if(sg == 0)
866 				continue;
867 			j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
868 				sname[sg->type&SG_TYPE],
869 				sg->type&SG_RONLY ? 'R' : ' ',
870 				sg->profile ? 'P' : ' ',
871 				sg->base, sg->top, sg->ref);
872 		}
873 		if(offset >= j)
874 			return 0;
875 		if(offset+n > j)
876 			n = j-offset;
877 		if(n == 0 && offset == 0)
878 			exhausted("segments");
879 		memmove(a, &statbuf[offset], n);
880 		return n;
881 
882 	case Qwait:
883 		if(!canqlock(&p->qwaitr))
884 			error(Einuse);
885 
886 		if(waserror()) {
887 			qunlock(&p->qwaitr);
888 			nexterror();
889 		}
890 
891 		lock(&p->exl);
892 		if(up == p && p->nchild == 0 && p->waitq == 0) {
893 			unlock(&p->exl);
894 			error(Enochild);
895 		}
896 		pid = p->pid;
897 		while(p->waitq == 0) {
898 			unlock(&p->exl);
899 			sleep(&p->waitr, haswaitq, p);
900 			if(p->pid != pid)
901 				error(Eprocdied);
902 			lock(&p->exl);
903 		}
904 		wq = p->waitq;
905 		p->waitq = wq->next;
906 		p->nwait--;
907 		unlock(&p->exl);
908 
909 		qunlock(&p->qwaitr);
910 		poperror();
911 		n = snprint(a, n, "%d %lud %lud %lud %q",
912 			wq->w.pid,
913 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
914 			wq->w.msg);
915 		free(wq);
916 		return n;
917 
918 	case Qns:
919 		qlock(&p->debug);
920 		if(waserror()){
921 			qunlock(&p->debug);
922 			nexterror();
923 		}
924 		if(p->pgrp == nil || p->pid != PID(c->qid))
925 			error(Eprocdied);
926 		mw = c->aux;
927 		if(mw->cddone){
928 			qunlock(&p->debug);
929 			poperror();
930 			return 0;
931 		}
932 		mntscan(mw, p);
933 		if(mw->mh == 0){
934 			mw->cddone = 1;
935 			i = snprint(a, n, "cd %s\n", p->dot->path->s);
936 			qunlock(&p->debug);
937 			poperror();
938 			return i;
939 		}
940 		int2flag(mw->cm->mflag, flag);
941 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
942 			srv = srvname(mw->cm->to->mchan);
943 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
944 				srv==nil? mw->cm->to->mchan->path->s : srv,
945 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
946 			free(srv);
947 		}else
948 			i = snprint(a, n, "bind %s %s %s\n", flag,
949 				mw->cm->to->path->s, mw->mh->from->path->s);
950 		qunlock(&p->debug);
951 		poperror();
952 		return i;
953 
954 	case Qnoteid:
955 		return readnum(offset, va, n, p->noteid, NUMSIZE);
956 	case Qfd:
957 		return procfds(p, va, n, offset);
958 	}
959 	error(Egreg);
960 	return 0;		/* not reached */
961 }
962 
963 void
964 mntscan(Mntwalk *mw, Proc *p)
965 {
966 	Pgrp *pg;
967 	Mount *t;
968 	Mhead *f;
969 	int nxt, i;
970 	ulong last, bestmid;
971 
972 	pg = p->pgrp;
973 	rlock(&pg->ns);
974 
975 	nxt = 0;
976 	bestmid = ~0;
977 
978 	last = 0;
979 	if(mw->mh)
980 		last = mw->cm->mountid;
981 
982 	for(i = 0; i < MNTHASH; i++) {
983 		for(f = pg->mnthash[i]; f; f = f->hash) {
984 			for(t = f->mount; t; t = t->next) {
985 				if(mw->mh == 0 ||
986 				  (t->mountid > last && t->mountid < bestmid)) {
987 					mw->cm = t;
988 					mw->mh = f;
989 					bestmid = mw->cm->mountid;
990 					nxt = 1;
991 				}
992 			}
993 		}
994 	}
995 	if(nxt == 0)
996 		mw->mh = 0;
997 
998 	runlock(&pg->ns);
999 }
1000 
1001 static long
1002 procwrite(Chan *c, void *va, long n, vlong off)
1003 {
1004 	int id, m;
1005 	Proc *p, *t, *et;
1006 	char *a, *arg, buf[ERRMAX];
1007 	ulong offset = off;
1008 
1009 	a = va;
1010 	if(c->qid.type & QTDIR)
1011 		error(Eisdir);
1012 
1013 	p = proctab(SLOT(c->qid));
1014 
1015 	/* Use the remembered noteid in the channel rather
1016 	 * than the process pgrpid
1017 	 */
1018 	if(QID(c->qid) == Qnotepg) {
1019 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1020 		return n;
1021 	}
1022 
1023 	qlock(&p->debug);
1024 	if(waserror()){
1025 		qunlock(&p->debug);
1026 		nexterror();
1027 	}
1028 	if(p->pid != PID(c->qid))
1029 		error(Eprocdied);
1030 
1031 	switch(QID(c->qid)){
1032 	case Qargs:
1033 		if(n == 0)
1034 			error(Eshort);
1035 		if(n >= ERRMAX)
1036 			error(Etoobig);
1037 		arg = malloc(n+1);
1038 		if(arg == nil)
1039 			error(Enomem);
1040 		memmove(arg, va, n);
1041 		m = n;
1042 		if(arg[m-1] != 0)
1043 			arg[m++] = 0;
1044 		free(p->args);
1045 		p->nargs = m;
1046 		p->args = arg;
1047 		p->setargs = 1;
1048 		break;
1049 
1050 	case Qmem:
1051 		if(p->state != Stopped)
1052 			error(Ebadctl);
1053 
1054 		n = procctlmemio(p, offset, n, va, 0);
1055 		break;
1056 
1057 	case Qregs:
1058 		if(offset >= sizeof(Ureg))
1059 			n = 0;
1060 		else if(offset+n > sizeof(Ureg))
1061 			n = sizeof(Ureg) - offset;
1062 		if(p->dbgreg == 0)
1063 			error(Enoreg);
1064 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1065 		break;
1066 
1067 	case Qfpregs:
1068 		if(offset >= sizeof(FPsave))
1069 			n = 0;
1070 		else if(offset+n > sizeof(FPsave))
1071 			n = sizeof(FPsave) - offset;
1072 		memmove((uchar*)&p->fpsave+offset, va, n);
1073 		break;
1074 
1075 	case Qctl:
1076 		procctlreq(p, va, n);
1077 		break;
1078 
1079 	case Qnote:
1080 		if(p->kp)
1081 			error(Eperm);
1082 		if(n >= ERRMAX-1)
1083 			error(Etoobig);
1084 		memmove(buf, va, n);
1085 		buf[n] = 0;
1086 		if(!postnote(p, 0, buf, NUser))
1087 			error("note not posted");
1088 		break;
1089 	case Qnoteid:
1090 		id = atoi(a);
1091 		if(id == p->pid) {
1092 			p->noteid = id;
1093 			break;
1094 		}
1095 		t = proctab(0);
1096 		for(et = t+conf.nproc; t < et; t++) {
1097 			if(t->state == Dead)
1098 				continue;
1099 			if(id == t->noteid) {
1100 				if(strcmp(p->user, t->user) != 0)
1101 					error(Eperm);
1102 				p->noteid = id;
1103 				break;
1104 			}
1105 		}
1106 		if(p->noteid != id)
1107 			error(Ebadarg);
1108 		break;
1109 	default:
1110 		pprint("unknown qid in procwrite\n");
1111 		error(Egreg);
1112 	}
1113 	poperror();
1114 	qunlock(&p->debug);
1115 	return n;
1116 }
1117 
1118 Dev procdevtab = {
1119 	'p',
1120 	"proc",
1121 
1122 	devreset,
1123 	procinit,
1124 	devshutdown,
1125 	procattach,
1126 	procwalk,
1127 	procstat,
1128 	procopen,
1129 	devcreate,
1130 	procclose,
1131 	procread,
1132 	devbread,
1133 	procwrite,
1134 	devbwrite,
1135 	devremove,
1136 	procwstat,
1137 };
1138 
1139 Chan*
1140 proctext(Chan *c, Proc *p)
1141 {
1142 	Chan *tc;
1143 	Image *i;
1144 	Segment *s;
1145 
1146 	s = p->seg[TSEG];
1147 	if(s == 0)
1148 		error(Enonexist);
1149 	if(p->state==Dead)
1150 		error(Eprocdied);
1151 
1152 	lock(s);
1153 	i = s->image;
1154 	if(i == 0) {
1155 		unlock(s);
1156 		error(Eprocdied);
1157 	}
1158 	unlock(s);
1159 
1160 	lock(i);
1161 	if(waserror()) {
1162 		unlock(i);
1163 		nexterror();
1164 	}
1165 
1166 	tc = i->c;
1167 	if(tc == 0)
1168 		error(Eprocdied);
1169 
1170 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1171 		cclose(tc);
1172 		error(Eprocdied);
1173 	}
1174 
1175 	if(p->pid != PID(c->qid))
1176 		error(Eprocdied);
1177 
1178 	unlock(i);
1179 	poperror();
1180 
1181 	return tc;
1182 }
1183 
1184 void
1185 procstopwait(Proc *p, int ctl)
1186 {
1187 	int pid;
1188 
1189 	if(p->pdbg)
1190 		error(Einuse);
1191 	if(procstopped(p) || p->state == Broken)
1192 		return;
1193 
1194 	if(ctl != 0)
1195 		p->procctl = ctl;
1196 	p->pdbg = up;
1197 	pid = p->pid;
1198 	qunlock(&p->debug);
1199 	up->psstate = "Stopwait";
1200 	if(waserror()) {
1201 		p->pdbg = 0;
1202 		qlock(&p->debug);
1203 		nexterror();
1204 	}
1205 	sleep(&up->sleep, procstopped, p);
1206 	poperror();
1207 	qlock(&p->debug);
1208 	if(p->pid != pid)
1209 		error(Eprocdied);
1210 }
1211 
1212 static void
1213 procctlcloseone(Proc *p, Fgrp *f, int fd)
1214 {
1215 	Chan *c;
1216 
1217 	c = f->fd[fd];
1218 	if(c == nil)
1219 		return;
1220 	f->fd[fd] = nil;
1221 	unlock(f);
1222 	qunlock(&p->debug);
1223 	cclose(c);
1224 	qlock(&p->debug);
1225 	lock(f);
1226 }
1227 
1228 void
1229 procctlclosefiles(Proc *p, int all, int fd)
1230 {
1231 	int i;
1232 	Fgrp *f;
1233 
1234 	f = p->fgrp;
1235 	if(f == nil)
1236 		error(Eprocdied);
1237 
1238 	lock(f);
1239 	f->ref++;
1240 	if(all)
1241 		for(i = 0; i < f->maxfd; i++)
1242 			procctlcloseone(p, f, i);
1243 	else
1244 		procctlcloseone(p, f, fd);
1245 	unlock(f);
1246 	closefgrp(f);
1247 }
1248 
1249 static char *
1250 parsetime(vlong *rt, char *s)
1251 {
1252 	uvlong ticks;
1253 	ulong l;
1254 	char *e, *p;
1255 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1256 
1257 	if (s == nil)
1258 		return("missing value");
1259 	ticks=strtoul(s, &e, 10);
1260 	if (*e == '.'){
1261 		p = e+1;
1262 		l = strtoul(p, &e, 10);
1263 		if(e-p > nelem(p10))
1264 			return "too many digits after decimal point";
1265 		if(e-p == 0)
1266 			return "ill-formed number";
1267 		l *= p10[e-p-1];
1268 	}else
1269 		l = 0;
1270 	if (*e == '\0' || strcmp(e, "s") == 0){
1271 		ticks = 1000000000 * ticks + l;
1272 	}else if (strcmp(e, "ms") == 0){
1273 		ticks = 1000000 * ticks + l/1000;
1274 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1275 		ticks = 1000 * ticks + l/1000000;
1276 	}else if (strcmp(e, "ns") != 0)
1277 		return "unrecognized unit";
1278 	*rt = ticks;
1279 	return nil;
1280 }
1281 
1282 void
1283 procctlreq(Proc *p, char *va, int n)
1284 {
1285 	Segment *s;
1286 	int npc, pri;
1287 	Cmdbuf *cb;
1288 	Cmdtab *ct;
1289 	vlong time;
1290 	char *e;
1291 	void (*pt)(Proc*, int, vlong);
1292 
1293 	if(p->kp)	/* no ctl requests to kprocs */
1294 		error(Eperm);
1295 
1296 	cb = parsecmd(va, n);
1297 	if(waserror()){
1298 		free(cb);
1299 		nexterror();
1300 	}
1301 
1302 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1303 
1304 	switch(ct->index){
1305 	case CMclose:
1306 		procctlclosefiles(p, 0, atoi(cb->f[1]));
1307 		break;
1308 	case CMclosefiles:
1309 		procctlclosefiles(p, 1, 0);
1310 		break;
1311 	case CMhang:
1312 		p->hang = 1;
1313 		break;
1314 	case CMkill:
1315 		switch(p->state) {
1316 		case Broken:
1317 			unbreak(p);
1318 			break;
1319 		case Stopped:
1320 			p->procctl = Proc_exitme;
1321 			postnote(p, 0, "sys: killed", NExit);
1322 			ready(p);
1323 			break;
1324 		default:
1325 			p->procctl = Proc_exitme;
1326 			postnote(p, 0, "sys: killed", NExit);
1327 		}
1328 		break;
1329 	case CMnohang:
1330 		p->hang = 0;
1331 		break;
1332 	case CMnoswap:
1333 		p->noswap = 1;
1334 		break;
1335 	case CMpri:
1336 		pri = atoi(cb->f[1]);
1337 		if(pri > PriNormal && !iseve())
1338 			error(Eperm);
1339 		procpriority(p, pri, 0);
1340 		break;
1341 	case CMfixedpri:
1342 		pri = atoi(cb->f[1]);
1343 		if(pri > PriNormal && !iseve())
1344 			error(Eperm);
1345 		procpriority(p, pri, 1);
1346 		break;
1347 	case CMprivate:
1348 		p->privatemem = 1;
1349 		break;
1350 	case CMprofile:
1351 		s = p->seg[TSEG];
1352 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1353 			error(Ebadctl);
1354 		if(s->profile != 0)
1355 			free(s->profile);
1356 		npc = (s->top-s->base)>>LRESPROF;
1357 		s->profile = malloc(npc*sizeof(*s->profile));
1358 		if(s->profile == 0)
1359 			error(Enomem);
1360 		break;
1361 	case CMstart:
1362 		if(p->state != Stopped)
1363 			error(Ebadctl);
1364 		ready(p);
1365 		break;
1366 	case CMstartstop:
1367 		if(p->state != Stopped)
1368 			error(Ebadctl);
1369 		p->procctl = Proc_traceme;
1370 		ready(p);
1371 		procstopwait(p, Proc_traceme);
1372 		break;
1373 	case CMstartsyscall:
1374 		if(p->state != Stopped)
1375 			error(Ebadctl);
1376 		p->procctl = Proc_tracesyscall;
1377 		ready(p);
1378 		procstopwait(p, Proc_tracesyscall);
1379 		break;
1380 	case CMstop:
1381 		procstopwait(p, Proc_stopme);
1382 		break;
1383 	case CMwaitstop:
1384 		procstopwait(p, 0);
1385 		break;
1386 	case CMwired:
1387 		procwired(p, atoi(cb->f[1]));
1388 		break;
1389 	case CMtrace:
1390 		switch(cb->nf){
1391 		case 1:
1392 			p->trace ^= 1;
1393 			break;
1394 		case 2:
1395 			p->trace = (atoi(cb->f[1]) != 0);
1396 			break;
1397 		default:
1398 			error("args");
1399 		}
1400 		break;
1401 	/* real time */
1402 	case CMperiod:
1403 		if(p->edf == nil)
1404 			edfinit(p);
1405 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1406 			error(e);
1407 		edfstop(p);
1408 		p->edf->T = time/1000;	/* Edf times are in µs */
1409 		break;
1410 	case CMdeadline:
1411 		if(p->edf == nil)
1412 			edfinit(p);
1413 		if(e=parsetime(&time, cb->f[1]))
1414 			error(e);
1415 		edfstop(p);
1416 		p->edf->D = time/1000;
1417 		break;
1418 	case CMcost:
1419 		if(p->edf == nil)
1420 			edfinit(p);
1421 		if(e=parsetime(&time, cb->f[1]))
1422 			error(e);
1423 		edfstop(p);
1424 		p->edf->C = time/1000;
1425 		break;
1426 	case CMsporadic:
1427 		if(p->edf == nil)
1428 			edfinit(p);
1429 		p->edf->flags |= Sporadic;
1430 		break;
1431 	case CMdeadlinenotes:
1432 		if(p->edf == nil)
1433 			edfinit(p);
1434 		p->edf->flags |= Sendnotes;
1435 		break;
1436 	case CMadmit:
1437 		if(p->edf == 0)
1438 			error("edf params");
1439 		if(e = edfadmit(p))
1440 			error(e);
1441 		break;
1442 	case CMextra:
1443 		if(p->edf == nil)
1444 			edfinit(p);
1445 		p->edf->flags |= Extratime;
1446 		break;
1447 	case CMexpel:
1448 		if(p->edf)
1449 			edfstop(p);
1450 		break;
1451 	case CMevent:
1452 		pt = proctrace;
1453 		if(up->trace && pt)
1454 			pt(up, SUser, 0);
1455 		break;
1456 	}
1457 
1458 	poperror();
1459 	free(cb);
1460 }
1461 
1462 int
1463 procstopped(void *a)
1464 {
1465 	Proc *p = a;
1466 	return p->state == Stopped;
1467 }
1468 
1469 int
1470 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1471 {
1472 	KMap *k;
1473 	Pte *pte;
1474 	Page *pg;
1475 	Segment *s;
1476 	ulong soff, l;
1477 	char *a = va, *b;
1478 
1479 	for(;;) {
1480 		s = seg(p, offset, 1);
1481 		if(s == 0)
1482 			error(Ebadarg);
1483 
1484 		if(offset+n >= s->top)
1485 			n = s->top-offset;
1486 
1487 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1488 			s = txt2data(p, s);
1489 
1490 		s->steal++;
1491 		soff = offset-s->base;
1492 		if(waserror()) {
1493 			s->steal--;
1494 			nexterror();
1495 		}
1496 		if(fixfault(s, offset, read, 0) == 0)
1497 			break;
1498 		poperror();
1499 		s->steal--;
1500 	}
1501 	poperror();
1502 	pte = s->map[soff/PTEMAPMEM];
1503 	if(pte == 0)
1504 		panic("procctlmemio");
1505 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1506 	if(pagedout(pg))
1507 		panic("procctlmemio1");
1508 
1509 	l = BY2PG - (offset&(BY2PG-1));
1510 	if(n > l)
1511 		n = l;
1512 
1513 	k = kmap(pg);
1514 	if(waserror()) {
1515 		s->steal--;
1516 		kunmap(k);
1517 		nexterror();
1518 	}
1519 	b = (char*)VA(k);
1520 	b += offset&(BY2PG-1);
1521 	if(read == 1)
1522 		memmove(a, b, n);	/* This can fault */
1523 	else
1524 		memmove(b, a, n);
1525 	kunmap(k);
1526 	poperror();
1527 
1528 	/* Ensure the process sees text page changes */
1529 	if(s->flushme)
1530 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1531 
1532 	s->steal--;
1533 
1534 	if(read == 0)
1535 		p->newtlb = 1;
1536 
1537 	return n;
1538 }
1539 
1540 Segment*
1541 txt2data(Proc *p, Segment *s)
1542 {
1543 	int i;
1544 	Segment *ps;
1545 
1546 	ps = newseg(SG_DATA, s->base, s->size);
1547 	ps->image = s->image;
1548 	incref(ps->image);
1549 	ps->fstart = s->fstart;
1550 	ps->flen = s->flen;
1551 	ps->flushme = 1;
1552 
1553 	qlock(&p->seglock);
1554 	for(i = 0; i < NSEG; i++)
1555 		if(p->seg[i] == s)
1556 			break;
1557 	if(i == NSEG)
1558 		panic("segment gone");
1559 
1560 	qunlock(&s->lk);
1561 	putseg(s);
1562 	qlock(&ps->lk);
1563 	p->seg[i] = ps;
1564 	qunlock(&p->seglock);
1565 
1566 	return ps;
1567 }
1568 
1569 Segment*
1570 data2txt(Segment *s)
1571 {
1572 	Segment *ps;
1573 
1574 	ps = newseg(SG_TEXT, s->base, s->size);
1575 	ps->image = s->image;
1576 	incref(ps->image);
1577 	ps->fstart = s->fstart;
1578 	ps->flen = s->flen;
1579 	ps->flushme = 1;
1580 
1581 	return ps;
1582 }
1583