xref: /plan9-contrib/sys/src/9/port/devproc.c (revision 3468a4915d661daa200976acc4f80f51aae144b2)
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 	Qsyscall,
34 };
35 
36 enum
37 {
38 	CMclose,
39 	CMclosefiles,
40 	CMfixedpri,
41 	CMhang,
42 	CMkill,
43 	CMnohang,
44 	CMnoswap,
45 	CMpri,
46 	CMprivate,
47 	CMprofile,
48 	CMstart,
49 	CMstartstop,
50 	CMstartsyscall,
51 	CMstop,
52 	CMwaitstop,
53 	CMwired,
54 	CMtrace,
55 	/* real time */
56 	CMperiod,
57 	CMdeadline,
58 	CMcost,
59 	CMsporadic,
60 	CMdeadlinenotes,
61 	CMadmit,
62 	CMextra,
63 	CMexpel,
64 	CMevent,
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 	"syscall",	{Qsyscall},	0,			0400,
98 };
99 
100 static
101 Cmdtab proccmd[] = {
102 	CMclose,		"close",		2,
103 	CMclosefiles,		"closefiles",		1,
104 	CMfixedpri,		"fixedpri",		2,
105 	CMhang,			"hang",			1,
106 	CMnohang,		"nohang",		1,
107 	CMnoswap,		"noswap",		1,
108 	CMkill,			"kill",			1,
109 	CMpri,			"pri",			2,
110 	CMprivate,		"private",		1,
111 	CMprofile,		"profile",		1,
112 	CMstart,		"start",		1,
113 	CMstartstop,		"startstop",		1,
114 	CMstartsyscall,		"startsyscall",		1,
115 	CMstop,			"stop",			1,
116 	CMwaitstop,		"waitstop",		1,
117 	CMwired,		"wired",		2,
118 	CMtrace,		"trace",		0,
119 	CMperiod,		"period",		2,
120 	CMdeadline,		"deadline",		2,
121 	CMcost,			"cost",			2,
122 	CMsporadic,		"sporadic",		1,
123 	CMdeadlinenotes,	"deadlinenotes",	1,
124 	CMadmit,		"admit",		1,
125 	CMextra,		"extra",		1,
126 	CMexpel,		"expel",		1,
127 	CMevent,		"event",		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 	case Qsyscall:
419 		nonone(p);
420 		break;
421 
422 	case Qns:
423 		if(omode != OREAD)
424 			error(Eperm);
425 		c->aux = malloc(sizeof(Mntwalk));
426 		break;
427 
428 	case Qnotepg:
429 		nonone(p);
430 		pg = p->pgrp;
431 		if(pg == nil)
432 			error(Eprocdied);
433 		if(omode!=OWRITE || pg->pgrpid == 1)
434 			error(Eperm);
435 		c->pgrpid.path = pg->pgrpid+1;
436 		c->pgrpid.vers = p->noteid;
437 		break;
438 
439 	default:
440 		pprint("procopen %#lux\n", QID(c->qid));
441 		error(Egreg);
442 	}
443 
444 	/* Affix pid to qid */
445 	if(p->state != Dead)
446 		c->qid.vers = p->pid;
447 
448 	/* make sure the process slot didn't get reallocated while we were playing */
449 	coherence();
450 	if(p->pid != pid)
451 		error(Eprocdied);
452 
453 	tc = devopen(c, omode, 0, 0, procgen);
454 	qunlock(&p->debug);
455 	poperror();
456 
457 	return tc;
458 }
459 
460 static int
461 procwstat(Chan *c, uchar *db, int n)
462 {
463 	Proc *p;
464 	Dir *d;
465 
466 	if(c->qid.type&QTDIR)
467 		error(Eperm);
468 
469 	if(QID(c->qid) == Qtrace)
470 		return devwstat(c, db, n);
471 
472 	p = proctab(SLOT(c->qid));
473 	nonone(p);
474 	d = nil;
475 	if(waserror()){
476 		free(d);
477 		qunlock(&p->debug);
478 		nexterror();
479 	}
480 	qlock(&p->debug);
481 
482 	if(p->pid != PID(c->qid))
483 		error(Eprocdied);
484 
485 	if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
486 		error(Eperm);
487 
488 	d = smalloc(sizeof(Dir)+n);
489 	n = convM2D(db, n, &d[0], (char*)&d[1]);
490 	if(n == 0)
491 		error(Eshortstat);
492 	if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
493 		if(strcmp(up->user, eve) != 0)
494 			error(Eperm);
495 		else
496 			kstrdup(&p->user, d->uid);
497 	}
498 	if(d->mode != ~0UL)
499 		p->procmode = d->mode&0777;
500 
501 	poperror();
502 	free(d);
503 	qunlock(&p->debug);
504 	return n;
505 }
506 
507 
508 static long
509 procoffset(long offset, char *va, int *np)
510 {
511 	if(offset > 0) {
512 		offset -= *np;
513 		if(offset < 0) {
514 			memmove(va, va+*np+offset, -offset);
515 			*np = -offset;
516 		}
517 		else
518 			*np = 0;
519 	}
520 	return offset;
521 }
522 
523 static int
524 procqidwidth(Chan *c)
525 {
526 	char buf[32];
527 
528 	return sprint(buf, "%lud", c->qid.vers);
529 }
530 
531 int
532 procfdprint(Chan *c, int fd, int w, char *s, int ns)
533 {
534 	int n;
535 
536 	if(w == 0)
537 		w = procqidwidth(c);
538 	n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
539 		fd,
540 		&"r w rw"[(c->mode&3)<<1],
541 		devtab[c->type]->dc, c->dev,
542 		c->qid.path, w, c->qid.vers, c->qid.type,
543 		c->iounit, c->offset, c->path->s);
544 	return n;
545 }
546 
547 static int
548 procfds(Proc *p, char *va, int count, long offset)
549 {
550 	Fgrp *f;
551 	Chan *c;
552 	char buf[256];
553 	int n, i, w, ww;
554 	char *a;
555 
556 	/* print to buf to avoid holding fgrp lock while writing to user space */
557 	if(count > sizeof buf)
558 		count = sizeof buf;
559 	a = buf;
560 
561 	qlock(&p->debug);
562 	f = p->fgrp;
563 	if(f == nil){
564 		qunlock(&p->debug);
565 		return 0;
566 	}
567 	lock(f);
568 	if(waserror()){
569 		unlock(f);
570 		qunlock(&p->debug);
571 		nexterror();
572 	}
573 
574 	n = readstr(0, a, count, p->dot->path->s);
575 	n += snprint(a+n, count-n, "\n");
576 	offset = procoffset(offset, a, &n);
577 	/* compute width of qid.path */
578 	w = 0;
579 	for(i = 0; i <= f->maxfd; i++) {
580 		c = f->fd[i];
581 		if(c == nil)
582 			continue;
583 		ww = procqidwidth(c);
584 		if(ww > w)
585 			w = ww;
586 	}
587 	for(i = 0; i <= f->maxfd; i++) {
588 		c = f->fd[i];
589 		if(c == nil)
590 			continue;
591 		n += procfdprint(c, i, w, a+n, count-n);
592 		offset = procoffset(offset, a, &n);
593 	}
594 	unlock(f);
595 	qunlock(&p->debug);
596 	poperror();
597 
598 	/* copy result to user space, now that locks are released */
599 	memmove(va, buf, n);
600 
601 	return n;
602 }
603 
604 static void
605 procclose(Chan * c)
606 {
607 	if(QID(c->qid) == Qtrace){
608 		lock(&tlock);
609 		if(topens > 0)
610 			topens--;
611 		if(topens == 0)
612 			proctrace = nil;
613 		unlock(&tlock);
614 	}
615 	if(QID(c->qid) == Qns && c->aux != 0)
616 		free(c->aux);
617 }
618 
619 static void
620 int2flag(int flag, char *s)
621 {
622 	if(flag == 0){
623 		*s = '\0';
624 		return;
625 	}
626 	*s++ = '-';
627 	if(flag & MAFTER)
628 		*s++ = 'a';
629 	if(flag & MBEFORE)
630 		*s++ = 'b';
631 	if(flag & MCREATE)
632 		*s++ = 'c';
633 	if(flag & MCACHE)
634 		*s++ = 'C';
635 	*s = '\0';
636 }
637 
638 static int
639 procargs(Proc *p, char *buf, int nbuf)
640 {
641 	int j, k, m;
642 	char *a;
643 	int n;
644 
645 	a = p->args;
646 	if(p->setargs){
647 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
648 		return strlen(buf);
649 	}
650 	n = p->nargs;
651 	for(j = 0; j < nbuf - 1; j += m){
652 		if(n <= 0)
653 			break;
654 		if(j != 0)
655 			buf[j++] = ' ';
656 		m = snprint(buf+j, nbuf-j, "%q",  a);
657 		k = strlen(a) + 1;
658 		a += k;
659 		n -= k;
660 	}
661 	return j;
662 }
663 
664 static int
665 eventsavailable(void *)
666 {
667 	return tproduced > tconsumed;
668 }
669 
670 static long
671 procread(Chan *c, void *va, long n, vlong off)
672 {
673 	/* NSEG*32 was too small for worst cases */
674 	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
675 	int i, j, m, navail, ne, pid, rsize;
676 	long l;
677 	uchar *rptr;
678 	ulong offset;
679 	Confmem *cm;
680 	Mntwalk *mw;
681 	Proc *p;
682 	Segment *sg, *s;
683 	Ureg kur;
684 	Waitq *wq;
685 
686 	a = va;
687 	offset = off;
688 
689 	if(c->qid.type & QTDIR)
690 		return devdirread(c, a, n, 0, 0, procgen);
691 
692 	if(QID(c->qid) == Qtrace){
693 		if(!eventsavailable(nil))
694 			return 0;
695 
696 		rptr = (uchar*)va;
697 		navail = tproduced - tconsumed;
698 		if(navail > n / sizeof(Traceevent))
699 			navail = n / sizeof(Traceevent);
700 		while(navail > 0) {
701 			ne = ((tconsumed & Emask) + navail > Nevents)?
702 					Nevents - (tconsumed & Emask): navail;
703 			memmove(rptr, &tevents[tconsumed & Emask],
704 					ne * sizeof(Traceevent));
705 
706 			tconsumed += ne;
707 			rptr += ne * sizeof(Traceevent);
708 			navail -= ne;
709 		}
710 		return rptr - (uchar*)va;
711 	}
712 
713 	p = proctab(SLOT(c->qid));
714 	if(p->pid != PID(c->qid))
715 		error(Eprocdied);
716 
717 	switch(QID(c->qid)){
718 	case Qargs:
719 		qlock(&p->debug);
720 		j = procargs(p, up->genbuf, sizeof up->genbuf);
721 		qunlock(&p->debug);
722 		if(offset >= j)
723 			return 0;
724 		if(offset+n > j)
725 			n = j-offset;
726 		memmove(a, &up->genbuf[offset], n);
727 		return n;
728 	case Qsyscall:
729 		if(!p->syscalltrace)
730 			return 0;
731 		n = readstr(offset, a, n, p->syscalltrace);
732 		return n;
733 
734 	case Qmem:
735 		if(offset < KZERO)
736 			return procctlmemio(p, offset, n, va, 1);
737 
738 		if(!iseve())
739 			error(Eperm);
740 
741 		/* validate kernel addresses */
742 		if(offset < (ulong)end) {
743 			if(offset+n > (ulong)end)
744 				n = (ulong)end - offset;
745 			memmove(a, (char*)offset, n);
746 			return n;
747 		}
748 		for(i=0; i<nelem(conf.mem); i++){
749 			cm = &conf.mem[i];
750 			/* klimit-1 because klimit might be zero! */
751 			if(cm->kbase <= offset && offset <= cm->klimit-1){
752 				if(offset+n >= cm->klimit-1)
753 					n = cm->klimit - offset;
754 				memmove(a, (char*)offset, n);
755 				return n;
756 			}
757 		}
758 		error(Ebadarg);
759 
760 	case Qprofile:
761 		s = p->seg[TSEG];
762 		if(s == 0 || s->profile == 0)
763 			error("profile is off");
764 		i = (s->top-s->base)>>LRESPROF;
765 		i *= sizeof(*s->profile);
766 		if(offset >= i)
767 			return 0;
768 		if(offset+n > i)
769 			n = i - offset;
770 		memmove(a, ((char*)s->profile)+offset, n);
771 		return n;
772 
773 	case Qnote:
774 		qlock(&p->debug);
775 		if(waserror()){
776 			qunlock(&p->debug);
777 			nexterror();
778 		}
779 		if(p->pid != PID(c->qid))
780 			error(Eprocdied);
781 		if(n < 1)	/* must accept at least the '\0' */
782 			error(Etoosmall);
783 		if(p->nnote == 0)
784 			n = 0;
785 		else {
786 			m = strlen(p->note[0].msg) + 1;
787 			if(m > n)
788 				m = n;
789 			memmove(va, p->note[0].msg, m);
790 			((char*)va)[m-1] = '\0';
791 			p->nnote--;
792 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
793 			n = m;
794 		}
795 		if(p->nnote == 0)
796 			p->notepending = 0;
797 		poperror();
798 		qunlock(&p->debug);
799 		return n;
800 
801 	case Qproc:
802 		if(offset >= sizeof(Proc))
803 			return 0;
804 		if(offset+n > sizeof(Proc))
805 			n = sizeof(Proc) - offset;
806 		memmove(a, ((char*)p)+offset, n);
807 		return n;
808 
809 	case Qregs:
810 		rptr = (uchar*)p->dbgreg;
811 		rsize = sizeof(Ureg);
812 		goto regread;
813 
814 	case Qkregs:
815 		memset(&kur, 0, sizeof(Ureg));
816 		setkernur(&kur, p);
817 		rptr = (uchar*)&kur;
818 		rsize = sizeof(Ureg);
819 		goto regread;
820 
821 	case Qfpregs:
822 		rptr = (uchar*)&p->fpsave;
823 		rsize = sizeof(FPsave);
824 	regread:
825 		if(rptr == 0)
826 			error(Enoreg);
827 		if(offset >= rsize)
828 			return 0;
829 		if(offset+n > rsize)
830 			n = rsize - offset;
831 		memmove(a, rptr+offset, n);
832 		return n;
833 
834 	case Qstatus:
835 		if(offset >= STATSIZE)
836 			return 0;
837 		if(offset+n > STATSIZE)
838 			n = STATSIZE - offset;
839 
840 		sps = p->psstate;
841 		if(sps == 0)
842 			sps = statename[p->state];
843 		memset(statbuf, ' ', sizeof statbuf);
844 		memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
845 		memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
846 		memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
847 		j = 2*KNAMELEN + 12;
848 
849 		for(i = 0; i < 6; i++) {
850 			l = p->time[i];
851 			if(i == TReal)
852 				l = MACHP(0)->ticks - l;
853 			l = TK2MS(l);
854 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
855 		}
856 		/* ignore stack, which is mostly non-existent */
857 		l = 0;
858 		for(i=1; i<NSEG; i++){
859 			s = p->seg[i];
860 			if(s)
861 				l += s->top - s->base;
862 		}
863 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
864 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
865 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
866 		memmove(a, statbuf+offset, n);
867 		return n;
868 
869 	case Qsegment:
870 		j = 0;
871 		for(i = 0; i < NSEG; i++) {
872 			sg = p->seg[i];
873 			if(sg == 0)
874 				continue;
875 			j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
876 				sname[sg->type&SG_TYPE],
877 				sg->type&SG_RONLY ? 'R' : ' ',
878 				sg->profile ? 'P' : ' ',
879 				sg->base, sg->top, sg->ref);
880 		}
881 		if(offset >= j)
882 			return 0;
883 		if(offset+n > j)
884 			n = j-offset;
885 		if(n == 0 && offset == 0)
886 			exhausted("segments");
887 		memmove(a, &statbuf[offset], n);
888 		return n;
889 
890 	case Qwait:
891 		if(!canqlock(&p->qwaitr))
892 			error(Einuse);
893 
894 		if(waserror()) {
895 			qunlock(&p->qwaitr);
896 			nexterror();
897 		}
898 
899 		lock(&p->exl);
900 		if(up == p && p->nchild == 0 && p->waitq == 0) {
901 			unlock(&p->exl);
902 			error(Enochild);
903 		}
904 		pid = p->pid;
905 		while(p->waitq == 0) {
906 			unlock(&p->exl);
907 			sleep(&p->waitr, haswaitq, p);
908 			if(p->pid != pid)
909 				error(Eprocdied);
910 			lock(&p->exl);
911 		}
912 		wq = p->waitq;
913 		p->waitq = wq->next;
914 		p->nwait--;
915 		unlock(&p->exl);
916 
917 		qunlock(&p->qwaitr);
918 		poperror();
919 		n = snprint(a, n, "%d %lud %lud %lud %q",
920 			wq->w.pid,
921 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
922 			wq->w.msg);
923 		free(wq);
924 		return n;
925 
926 	case Qns:
927 		qlock(&p->debug);
928 		if(waserror()){
929 			qunlock(&p->debug);
930 			nexterror();
931 		}
932 		if(p->pgrp == nil || p->pid != PID(c->qid))
933 			error(Eprocdied);
934 		mw = c->aux;
935 		if(mw->cddone){
936 			qunlock(&p->debug);
937 			poperror();
938 			return 0;
939 		}
940 		mntscan(mw, p);
941 		if(mw->mh == 0){
942 			mw->cddone = 1;
943 			i = snprint(a, n, "cd %s\n", p->dot->path->s);
944 			qunlock(&p->debug);
945 			poperror();
946 			return i;
947 		}
948 		int2flag(mw->cm->mflag, flag);
949 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
950 			srv = srvname(mw->cm->to->mchan);
951 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
952 				srv==nil? mw->cm->to->mchan->path->s : srv,
953 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
954 			free(srv);
955 		}else
956 			i = snprint(a, n, "bind %s %s %s\n", flag,
957 				mw->cm->to->path->s, mw->mh->from->path->s);
958 		qunlock(&p->debug);
959 		poperror();
960 		return i;
961 
962 	case Qnoteid:
963 		return readnum(offset, va, n, p->noteid, NUMSIZE);
964 	case Qfd:
965 		return procfds(p, va, n, offset);
966 	}
967 	error(Egreg);
968 	return 0;		/* not reached */
969 }
970 
971 void
972 mntscan(Mntwalk *mw, Proc *p)
973 {
974 	Pgrp *pg;
975 	Mount *t;
976 	Mhead *f;
977 	int nxt, i;
978 	ulong last, bestmid;
979 
980 	pg = p->pgrp;
981 	rlock(&pg->ns);
982 
983 	nxt = 0;
984 	bestmid = ~0;
985 
986 	last = 0;
987 	if(mw->mh)
988 		last = mw->cm->mountid;
989 
990 	for(i = 0; i < MNTHASH; i++) {
991 		for(f = pg->mnthash[i]; f; f = f->hash) {
992 			for(t = f->mount; t; t = t->next) {
993 				if(mw->mh == 0 ||
994 				  (t->mountid > last && t->mountid < bestmid)) {
995 					mw->cm = t;
996 					mw->mh = f;
997 					bestmid = mw->cm->mountid;
998 					nxt = 1;
999 				}
1000 			}
1001 		}
1002 	}
1003 	if(nxt == 0)
1004 		mw->mh = 0;
1005 
1006 	runlock(&pg->ns);
1007 }
1008 
1009 static long
1010 procwrite(Chan *c, void *va, long n, vlong off)
1011 {
1012 	int id, m;
1013 	Proc *p, *t, *et;
1014 	char *a, *arg, buf[ERRMAX];
1015 	ulong offset = off;
1016 
1017 	a = va;
1018 	if(c->qid.type & QTDIR)
1019 		error(Eisdir);
1020 
1021 	p = proctab(SLOT(c->qid));
1022 
1023 	/* Use the remembered noteid in the channel rather
1024 	 * than the process pgrpid
1025 	 */
1026 	if(QID(c->qid) == Qnotepg) {
1027 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1028 		return n;
1029 	}
1030 
1031 	qlock(&p->debug);
1032 	if(waserror()){
1033 		qunlock(&p->debug);
1034 		nexterror();
1035 	}
1036 	if(p->pid != PID(c->qid))
1037 		error(Eprocdied);
1038 
1039 	switch(QID(c->qid)){
1040 	case Qargs:
1041 		if(n == 0)
1042 			error(Eshort);
1043 		if(n >= ERRMAX)
1044 			error(Etoobig);
1045 		arg = malloc(n+1);
1046 		if(arg == nil)
1047 			error(Enomem);
1048 		memmove(arg, va, n);
1049 		m = n;
1050 		if(arg[m-1] != 0)
1051 			arg[m++] = 0;
1052 		free(p->args);
1053 		p->nargs = m;
1054 		p->args = arg;
1055 		p->setargs = 1;
1056 		break;
1057 
1058 	case Qmem:
1059 		if(p->state != Stopped)
1060 			error(Ebadctl);
1061 
1062 		n = procctlmemio(p, offset, n, va, 0);
1063 		break;
1064 
1065 	case Qregs:
1066 		if(offset >= sizeof(Ureg))
1067 			n = 0;
1068 		else if(offset+n > sizeof(Ureg))
1069 			n = sizeof(Ureg) - offset;
1070 		if(p->dbgreg == 0)
1071 			error(Enoreg);
1072 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1073 		break;
1074 
1075 	case Qfpregs:
1076 		if(offset >= sizeof(FPsave))
1077 			n = 0;
1078 		else if(offset+n > sizeof(FPsave))
1079 			n = sizeof(FPsave) - offset;
1080 		memmove((uchar*)&p->fpsave+offset, va, n);
1081 		break;
1082 
1083 	case Qctl:
1084 		procctlreq(p, va, n);
1085 		break;
1086 
1087 	case Qnote:
1088 		if(p->kp)
1089 			error(Eperm);
1090 		if(n >= ERRMAX-1)
1091 			error(Etoobig);
1092 		memmove(buf, va, n);
1093 		buf[n] = 0;
1094 		if(!postnote(p, 0, buf, NUser))
1095 			error("note not posted");
1096 		break;
1097 	case Qnoteid:
1098 		id = atoi(a);
1099 		if(id == p->pid) {
1100 			p->noteid = id;
1101 			break;
1102 		}
1103 		t = proctab(0);
1104 		for(et = t+conf.nproc; t < et; t++) {
1105 			if(t->state == Dead)
1106 				continue;
1107 			if(id == t->noteid) {
1108 				if(strcmp(p->user, t->user) != 0)
1109 					error(Eperm);
1110 				p->noteid = id;
1111 				break;
1112 			}
1113 		}
1114 		if(p->noteid != id)
1115 			error(Ebadarg);
1116 		break;
1117 	default:
1118 		pprint("unknown qid in procwrite\n");
1119 		error(Egreg);
1120 	}
1121 	poperror();
1122 	qunlock(&p->debug);
1123 	return n;
1124 }
1125 
1126 Dev procdevtab = {
1127 	'p',
1128 	"proc",
1129 
1130 	devreset,
1131 	procinit,
1132 	devshutdown,
1133 	procattach,
1134 	procwalk,
1135 	procstat,
1136 	procopen,
1137 	devcreate,
1138 	procclose,
1139 	procread,
1140 	devbread,
1141 	procwrite,
1142 	devbwrite,
1143 	devremove,
1144 	procwstat,
1145 };
1146 
1147 Chan*
1148 proctext(Chan *c, Proc *p)
1149 {
1150 	Chan *tc;
1151 	Image *i;
1152 	Segment *s;
1153 
1154 	s = p->seg[TSEG];
1155 	if(s == 0)
1156 		error(Enonexist);
1157 	if(p->state==Dead)
1158 		error(Eprocdied);
1159 
1160 	lock(s);
1161 	i = s->image;
1162 	if(i == 0) {
1163 		unlock(s);
1164 		error(Eprocdied);
1165 	}
1166 	unlock(s);
1167 
1168 	lock(i);
1169 	if(waserror()) {
1170 		unlock(i);
1171 		nexterror();
1172 	}
1173 
1174 	tc = i->c;
1175 	if(tc == 0)
1176 		error(Eprocdied);
1177 
1178 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1179 		cclose(tc);
1180 		error(Eprocdied);
1181 	}
1182 
1183 	if(p->pid != PID(c->qid))
1184 		error(Eprocdied);
1185 
1186 	unlock(i);
1187 	poperror();
1188 
1189 	return tc;
1190 }
1191 
1192 void
1193 procstopwait(Proc *p, int ctl)
1194 {
1195 	int pid;
1196 
1197 	if(p->pdbg)
1198 		error(Einuse);
1199 	if(procstopped(p) || p->state == Broken)
1200 		return;
1201 
1202 	if(ctl != 0)
1203 		p->procctl = ctl;
1204 	p->pdbg = up;
1205 	pid = p->pid;
1206 	qunlock(&p->debug);
1207 	up->psstate = "Stopwait";
1208 	if(waserror()) {
1209 		p->pdbg = 0;
1210 		qlock(&p->debug);
1211 		nexterror();
1212 	}
1213 	sleep(&up->sleep, procstopped, p);
1214 	poperror();
1215 	qlock(&p->debug);
1216 	if(p->pid != pid)
1217 		error(Eprocdied);
1218 }
1219 
1220 static void
1221 procctlcloseone(Proc *p, Fgrp *f, int fd)
1222 {
1223 	Chan *c;
1224 
1225 	c = f->fd[fd];
1226 	if(c == nil)
1227 		return;
1228 	f->fd[fd] = nil;
1229 	unlock(f);
1230 	qunlock(&p->debug);
1231 	cclose(c);
1232 	qlock(&p->debug);
1233 	lock(f);
1234 }
1235 
1236 void
1237 procctlclosefiles(Proc *p, int all, int fd)
1238 {
1239 	int i;
1240 	Fgrp *f;
1241 
1242 	f = p->fgrp;
1243 	if(f == nil)
1244 		error(Eprocdied);
1245 
1246 	lock(f);
1247 	f->ref++;
1248 	if(all)
1249 		for(i = 0; i < f->maxfd; i++)
1250 			procctlcloseone(p, f, i);
1251 	else
1252 		procctlcloseone(p, f, fd);
1253 	unlock(f);
1254 	closefgrp(f);
1255 }
1256 
1257 static char *
1258 parsetime(vlong *rt, char *s)
1259 {
1260 	uvlong ticks;
1261 	ulong l;
1262 	char *e, *p;
1263 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1264 
1265 	if (s == nil)
1266 		return("missing value");
1267 	ticks=strtoul(s, &e, 10);
1268 	if (*e == '.'){
1269 		p = e+1;
1270 		l = strtoul(p, &e, 10);
1271 		if(e-p > nelem(p10))
1272 			return "too many digits after decimal point";
1273 		if(e-p == 0)
1274 			return "ill-formed number";
1275 		l *= p10[e-p-1];
1276 	}else
1277 		l = 0;
1278 	if (*e == '\0' || strcmp(e, "s") == 0){
1279 		ticks = 1000000000 * ticks + l;
1280 	}else if (strcmp(e, "ms") == 0){
1281 		ticks = 1000000 * ticks + l/1000;
1282 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1283 		ticks = 1000 * ticks + l/1000000;
1284 	}else if (strcmp(e, "ns") != 0)
1285 		return "unrecognized unit";
1286 	*rt = ticks;
1287 	return nil;
1288 }
1289 
1290 void
1291 procctlreq(Proc *p, char *va, int n)
1292 {
1293 	Segment *s;
1294 	int npc, pri;
1295 	Cmdbuf *cb;
1296 	Cmdtab *ct;
1297 	vlong time;
1298 	char *e;
1299 	void (*pt)(Proc*, int, vlong);
1300 
1301 	if(p->kp)	/* no ctl requests to kprocs */
1302 		error(Eperm);
1303 
1304 	cb = parsecmd(va, n);
1305 	if(waserror()){
1306 		free(cb);
1307 		nexterror();
1308 	}
1309 
1310 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1311 
1312 	switch(ct->index){
1313 	case CMclose:
1314 		procctlclosefiles(p, 0, atoi(cb->f[1]));
1315 		break;
1316 	case CMclosefiles:
1317 		procctlclosefiles(p, 1, 0);
1318 		break;
1319 	case CMhang:
1320 		p->hang = 1;
1321 		break;
1322 	case CMkill:
1323 		switch(p->state) {
1324 		case Broken:
1325 			unbreak(p);
1326 			break;
1327 		case Stopped:
1328 			p->procctl = Proc_exitme;
1329 			postnote(p, 0, "sys: killed", NExit);
1330 			ready(p);
1331 			break;
1332 		default:
1333 			p->procctl = Proc_exitme;
1334 			postnote(p, 0, "sys: killed", NExit);
1335 		}
1336 		break;
1337 	case CMnohang:
1338 		p->hang = 0;
1339 		break;
1340 	case CMnoswap:
1341 		p->noswap = 1;
1342 		break;
1343 	case CMpri:
1344 		pri = atoi(cb->f[1]);
1345 		if(pri > PriNormal && !iseve())
1346 			error(Eperm);
1347 		procpriority(p, pri, 0);
1348 		break;
1349 	case CMfixedpri:
1350 		pri = atoi(cb->f[1]);
1351 		if(pri > PriNormal && !iseve())
1352 			error(Eperm);
1353 		procpriority(p, pri, 1);
1354 		break;
1355 	case CMprivate:
1356 		p->privatemem = 1;
1357 		break;
1358 	case CMprofile:
1359 		s = p->seg[TSEG];
1360 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1361 			error(Ebadctl);
1362 		if(s->profile != 0)
1363 			free(s->profile);
1364 		npc = (s->top-s->base)>>LRESPROF;
1365 		s->profile = malloc(npc*sizeof(*s->profile));
1366 		if(s->profile == 0)
1367 			error(Enomem);
1368 		break;
1369 	case CMstart:
1370 		if(p->state != Stopped)
1371 			error(Ebadctl);
1372 		ready(p);
1373 		break;
1374 	case CMstartstop:
1375 		if(p->state != Stopped)
1376 			error(Ebadctl);
1377 		p->procctl = Proc_traceme;
1378 		ready(p);
1379 		procstopwait(p, Proc_traceme);
1380 		break;
1381 	case CMstartsyscall:
1382 		if(p->state != Stopped)
1383 			error(Ebadctl);
1384 		p->procctl = Proc_tracesyscall;
1385 		ready(p);
1386 		procstopwait(p, Proc_tracesyscall);
1387 		break;
1388 	case CMstop:
1389 		procstopwait(p, Proc_stopme);
1390 		break;
1391 	case CMwaitstop:
1392 		procstopwait(p, 0);
1393 		break;
1394 	case CMwired:
1395 		procwired(p, atoi(cb->f[1]));
1396 		break;
1397 	case CMtrace:
1398 		switch(cb->nf){
1399 		case 1:
1400 			p->trace ^= 1;
1401 			break;
1402 		case 2:
1403 			p->trace = (atoi(cb->f[1]) != 0);
1404 			break;
1405 		default:
1406 			error("args");
1407 		}
1408 		break;
1409 	/* real time */
1410 	case CMperiod:
1411 		if(p->edf == nil)
1412 			edfinit(p);
1413 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1414 			error(e);
1415 		edfstop(p);
1416 		p->edf->T = time/1000;	/* Edf times are in µs */
1417 		break;
1418 	case CMdeadline:
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->D = time/1000;
1425 		break;
1426 	case CMcost:
1427 		if(p->edf == nil)
1428 			edfinit(p);
1429 		if(e=parsetime(&time, cb->f[1]))
1430 			error(e);
1431 		edfstop(p);
1432 		p->edf->C = time/1000;
1433 		break;
1434 	case CMsporadic:
1435 		if(p->edf == nil)
1436 			edfinit(p);
1437 		p->edf->flags |= Sporadic;
1438 		break;
1439 	case CMdeadlinenotes:
1440 		if(p->edf == nil)
1441 			edfinit(p);
1442 		p->edf->flags |= Sendnotes;
1443 		break;
1444 	case CMadmit:
1445 		if(p->edf == 0)
1446 			error("edf params");
1447 		if(e = edfadmit(p))
1448 			error(e);
1449 		break;
1450 	case CMextra:
1451 		if(p->edf == nil)
1452 			edfinit(p);
1453 		p->edf->flags |= Extratime;
1454 		break;
1455 	case CMexpel:
1456 		if(p->edf)
1457 			edfstop(p);
1458 		break;
1459 	case CMevent:
1460 		pt = proctrace;
1461 		if(up->trace && pt)
1462 			pt(up, SUser, 0);
1463 		break;
1464 	}
1465 
1466 	poperror();
1467 	free(cb);
1468 }
1469 
1470 int
1471 procstopped(void *a)
1472 {
1473 	Proc *p = a;
1474 	return p->state == Stopped;
1475 }
1476 
1477 int
1478 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1479 {
1480 	KMap *k;
1481 	Pte *pte;
1482 	Page *pg;
1483 	Segment *s;
1484 	ulong soff, l;
1485 	char *a = va, *b;
1486 
1487 	for(;;) {
1488 		s = seg(p, offset, 1);
1489 		if(s == 0)
1490 			error(Ebadarg);
1491 
1492 		if(offset+n >= s->top)
1493 			n = s->top-offset;
1494 
1495 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1496 			s = txt2data(p, s);
1497 
1498 		s->steal++;
1499 		soff = offset-s->base;
1500 		if(waserror()) {
1501 			s->steal--;
1502 			nexterror();
1503 		}
1504 		if(fixfault(s, offset, read, 0) == 0)
1505 			break;
1506 		poperror();
1507 		s->steal--;
1508 	}
1509 	poperror();
1510 	pte = s->map[soff/PTEMAPMEM];
1511 	if(pte == 0)
1512 		panic("procctlmemio");
1513 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1514 	if(pagedout(pg))
1515 		panic("procctlmemio1");
1516 
1517 	l = BY2PG - (offset&(BY2PG-1));
1518 	if(n > l)
1519 		n = l;
1520 
1521 	k = kmap(pg);
1522 	if(waserror()) {
1523 		s->steal--;
1524 		kunmap(k);
1525 		nexterror();
1526 	}
1527 	b = (char*)VA(k);
1528 	b += offset&(BY2PG-1);
1529 	if(read == 1)
1530 		memmove(a, b, n);	/* This can fault */
1531 	else
1532 		memmove(b, a, n);
1533 	kunmap(k);
1534 	poperror();
1535 
1536 	/* Ensure the process sees text page changes */
1537 	if(s->flushme)
1538 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1539 
1540 	s->steal--;
1541 
1542 	if(read == 0)
1543 		p->newtlb = 1;
1544 
1545 	return n;
1546 }
1547 
1548 Segment*
1549 txt2data(Proc *p, Segment *s)
1550 {
1551 	int i;
1552 	Segment *ps;
1553 
1554 	ps = newseg(SG_DATA, s->base, s->size);
1555 	ps->image = s->image;
1556 	incref(ps->image);
1557 	ps->fstart = s->fstart;
1558 	ps->flen = s->flen;
1559 	ps->flushme = 1;
1560 
1561 	qlock(&p->seglock);
1562 	for(i = 0; i < NSEG; i++)
1563 		if(p->seg[i] == s)
1564 			break;
1565 	if(i == NSEG)
1566 		panic("segment gone");
1567 
1568 	qunlock(&s->lk);
1569 	putseg(s);
1570 	qlock(&ps->lk);
1571 	p->seg[i] = ps;
1572 	qunlock(&p->seglock);
1573 
1574 	return ps;
1575 }
1576 
1577 Segment*
1578 data2txt(Segment *s)
1579 {
1580 	Segment *ps;
1581 
1582 	ps = newseg(SG_TEXT, s->base, s->size);
1583 	ps->image = s->image;
1584 	incref(ps->image);
1585 	ps->fstart = s->fstart;
1586 	ps->flen = s->flen;
1587 	ps->flushme = 1;
1588 
1589 	return ps;
1590 }
1591