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