xref: /plan9/sys/src/9/port/devproc.c (revision 282e677fa45fb578cdb8bc2c412ac084c367776e)
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(id == t->noteid) {
1101 				if(strcmp(p->user, t->user) != 0)
1102 					error(Eperm);
1103 				p->noteid = id;
1104 				break;
1105 			}
1106 		}
1107 		if(p->noteid != id)
1108 			error(Ebadarg);
1109 		break;
1110 	default:
1111 		pprint("unknown qid in procwrite\n");
1112 		error(Egreg);
1113 	}
1114 	poperror();
1115 	qunlock(&p->debug);
1116 	return n;
1117 }
1118 
1119 Dev procdevtab = {
1120 	'p',
1121 	"proc",
1122 
1123 	devreset,
1124 	procinit,
1125 	devshutdown,
1126 	procattach,
1127 	procwalk,
1128 	procstat,
1129 	procopen,
1130 	devcreate,
1131 	procclose,
1132 	procread,
1133 	devbread,
1134 	procwrite,
1135 	devbwrite,
1136 	devremove,
1137 	procwstat,
1138 };
1139 
1140 Chan*
1141 proctext(Chan *c, Proc *p)
1142 {
1143 	Chan *tc;
1144 	Image *i;
1145 	Segment *s;
1146 
1147 	s = p->seg[TSEG];
1148 	if(s == 0)
1149 		error(Enonexist);
1150 	if(p->state==Dead)
1151 		error(Eprocdied);
1152 
1153 	lock(s);
1154 	i = s->image;
1155 	if(i == 0) {
1156 		unlock(s);
1157 		error(Eprocdied);
1158 	}
1159 	unlock(s);
1160 
1161 	lock(i);
1162 	if(waserror()) {
1163 		unlock(i);
1164 		nexterror();
1165 	}
1166 
1167 	tc = i->c;
1168 	if(tc == 0)
1169 		error(Eprocdied);
1170 
1171 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1172 		cclose(tc);
1173 		error(Eprocdied);
1174 	}
1175 
1176 	if(p->pid != PID(c->qid))
1177 		error(Eprocdied);
1178 
1179 	unlock(i);
1180 	poperror();
1181 
1182 	return tc;
1183 }
1184 
1185 void
1186 procstopwait(Proc *p, int ctl)
1187 {
1188 	int pid;
1189 
1190 	if(p->pdbg)
1191 		error(Einuse);
1192 	if(procstopped(p) || p->state == Broken)
1193 		return;
1194 
1195 	if(ctl != 0)
1196 		p->procctl = ctl;
1197 	p->pdbg = up;
1198 	pid = p->pid;
1199 	qunlock(&p->debug);
1200 	up->psstate = "Stopwait";
1201 	if(waserror()) {
1202 		p->pdbg = 0;
1203 		qlock(&p->debug);
1204 		nexterror();
1205 	}
1206 	sleep(&up->sleep, procstopped, p);
1207 	poperror();
1208 	qlock(&p->debug);
1209 	if(p->pid != pid)
1210 		error(Eprocdied);
1211 }
1212 
1213 static void
1214 procctlcloseone(Proc *p, Fgrp *f, int fd)
1215 {
1216 	Chan *c;
1217 
1218 	c = f->fd[fd];
1219 	if(c == nil)
1220 		return;
1221 	f->fd[fd] = nil;
1222 	unlock(f);
1223 	qunlock(&p->debug);
1224 	cclose(c);
1225 	qlock(&p->debug);
1226 	lock(f);
1227 }
1228 
1229 void
1230 procctlclosefiles(Proc *p, int all, int fd)
1231 {
1232 	int i;
1233 	Fgrp *f;
1234 
1235 	f = p->fgrp;
1236 	if(f == nil)
1237 		error(Eprocdied);
1238 
1239 	lock(f);
1240 	f->ref++;
1241 	if(all)
1242 		for(i = 0; i < f->maxfd; i++)
1243 			procctlcloseone(p, f, i);
1244 	else
1245 		procctlcloseone(p, f, fd);
1246 	unlock(f);
1247 	closefgrp(f);
1248 }
1249 
1250 static char *
1251 parsetime(vlong *rt, char *s)
1252 {
1253 	uvlong ticks;
1254 	ulong l;
1255 	char *e, *p;
1256 	static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1257 
1258 	if (s == nil)
1259 		return("missing value");
1260 	ticks=strtoul(s, &e, 10);
1261 	if (*e == '.'){
1262 		p = e+1;
1263 		l = strtoul(p, &e, 10);
1264 		if(e-p > nelem(p10))
1265 			return "too many digits after decimal point";
1266 		if(e-p == 0)
1267 			return "ill-formed number";
1268 		l *= p10[e-p-1];
1269 	}else
1270 		l = 0;
1271 	if (*e == '\0' || strcmp(e, "s") == 0){
1272 		ticks = 1000000000 * ticks + l;
1273 	}else if (strcmp(e, "ms") == 0){
1274 		ticks = 1000000 * ticks + l/1000;
1275 	}else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1276 		ticks = 1000 * ticks + l/1000000;
1277 	}else if (strcmp(e, "ns") != 0)
1278 		return "unrecognized unit";
1279 	*rt = ticks;
1280 	return nil;
1281 }
1282 
1283 void
1284 procctlreq(Proc *p, char *va, int n)
1285 {
1286 	Segment *s;
1287 	int npc, pri;
1288 	Cmdbuf *cb;
1289 	Cmdtab *ct;
1290 	vlong time;
1291 	char *e;
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 			postnote(p, 0, "sys: killed", NExit);
1321 			p->procctl = Proc_exitme;
1322 			ready(p);
1323 			break;
1324 		default:
1325 			postnote(p, 0, "sys: killed", NExit);
1326 			p->procctl = Proc_exitme;
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])?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]))
1406 			error(e);
1407 		edfstop(p);
1408 		p->edf->T = time;
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;
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;
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 	}
1452 
1453 	poperror();
1454 	free(cb);
1455 }
1456 
1457 int
1458 procstopped(void *a)
1459 {
1460 	Proc *p = a;
1461 	return p->state == Stopped;
1462 }
1463 
1464 int
1465 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1466 {
1467 	KMap *k;
1468 	Pte *pte;
1469 	Page *pg;
1470 	Segment *s;
1471 	ulong soff, l;
1472 	char *a = va, *b;
1473 
1474 	for(;;) {
1475 		s = seg(p, offset, 1);
1476 		if(s == 0)
1477 			error(Ebadarg);
1478 
1479 		if(offset+n >= s->top)
1480 			n = s->top-offset;
1481 
1482 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1483 			s = txt2data(p, s);
1484 
1485 		s->steal++;
1486 		soff = offset-s->base;
1487 		if(waserror()) {
1488 			s->steal--;
1489 			nexterror();
1490 		}
1491 		if(fixfault(s, offset, read, 0) == 0)
1492 			break;
1493 		poperror();
1494 		s->steal--;
1495 	}
1496 	poperror();
1497 	pte = s->map[soff/PTEMAPMEM];
1498 	if(pte == 0)
1499 		panic("procctlmemio");
1500 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1501 	if(pagedout(pg))
1502 		panic("procctlmemio1");
1503 
1504 	l = BY2PG - (offset&(BY2PG-1));
1505 	if(n > l)
1506 		n = l;
1507 
1508 	k = kmap(pg);
1509 	if(waserror()) {
1510 		s->steal--;
1511 		kunmap(k);
1512 		nexterror();
1513 	}
1514 	b = (char*)VA(k);
1515 	b += offset&(BY2PG-1);
1516 	if(read == 1)
1517 		memmove(a, b, n);	/* This can fault */
1518 	else
1519 		memmove(b, a, n);
1520 	kunmap(k);
1521 	poperror();
1522 
1523 	/* Ensure the process sees text page changes */
1524 	if(s->flushme)
1525 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1526 
1527 	s->steal--;
1528 
1529 	if(read == 0)
1530 		p->newtlb = 1;
1531 
1532 	return n;
1533 }
1534 
1535 Segment*
1536 txt2data(Proc *p, Segment *s)
1537 {
1538 	int i;
1539 	Segment *ps;
1540 
1541 	ps = newseg(SG_DATA, s->base, s->size);
1542 	ps->image = s->image;
1543 	incref(ps->image);
1544 	ps->fstart = s->fstart;
1545 	ps->flen = s->flen;
1546 	ps->flushme = 1;
1547 
1548 	qlock(&p->seglock);
1549 	for(i = 0; i < NSEG; i++)
1550 		if(p->seg[i] == s)
1551 			break;
1552 	if(p->seg[i] != s)
1553 		panic("segment gone");
1554 
1555 	qunlock(&s->lk);
1556 	putseg(s);
1557 	qlock(&ps->lk);
1558 	p->seg[i] = ps;
1559 	qunlock(&p->seglock);
1560 
1561 	return ps;
1562 }
1563 
1564 Segment*
1565 data2txt(Segment *s)
1566 {
1567 	Segment *ps;
1568 
1569 	ps = newseg(SG_TEXT, s->base, s->size);
1570 	ps->image = s->image;
1571 	incref(ps->image);
1572 	ps->fstart = s->fstart;
1573 	ps->flen = s->flen;
1574 	ps->flushme = 1;
1575 
1576 	return ps;
1577 }
1578