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