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