xref: /plan9-contrib/sys/src/9/port/devproc.c (revision d46c239f8612929b7dbade67d0d071633df3a15d)
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,			0660,
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 	if(p->setargs){
510 		snprint(buf, nbuf, "%s [%s]", p->text, p->args);
511 		return strlen(buf);
512 	}
513 	n = p->nargs;
514 	for(j = 0; j < nbuf - 1; j += m){
515 		if(n <= 0)
516 			break;
517 		if(j != 0)
518 			buf[j++] = ' ';
519 		m = snprint(buf+j, nbuf-j, "%q",  a);
520 		k = strlen(a) + 1;
521 		a += k;
522 		n -= k;
523 	}
524 	return j;
525 }
526 
527 static long
528 procread(Chan *c, void *va, long n, vlong off)
529 {
530 	int m;
531 	long l;
532 	Proc *p;
533 	Waitq *wq;
534 	Ureg kur;
535 	uchar *rptr;
536 	Mntwalk *mw;
537 	Segment *sg, *s;
538 	char *a = va, *sps;
539 	int i, j, rsize, pid;
540 	char statbuf[NSEG*32], *srv, flag[10];
541 	ulong offset = off;
542 
543 	if(c->qid.type & QTDIR)
544 		return devdirread(c, a, n, 0, 0, procgen);
545 
546 	p = proctab(SLOT(c->qid));
547 	if(p->pid != PID(c->qid))
548 		error(Eprocdied);
549 
550 	switch(QID(c->qid)){
551 	case Qargs:
552 		qlock(&p->debug);
553 		j = procargs(p, p->genbuf, sizeof p->genbuf);
554 		qunlock(&p->debug);
555 		if(offset >= j)
556 			return 0;
557 		if(offset+n > j)
558 			n = j-offset;
559 		memmove(a, &p->genbuf[offset], n);
560 		return n;
561 
562 	case Qmem:
563 		if(offset < KZERO
564 		|| (offset >= USTKTOP-USTKSIZE && offset < USTKTOP))
565 			return procctlmemio(p, offset, n, va, 1);
566 
567 		if(!iseve())
568 			error(Eperm);
569 
570 		/* validate kernel addresses */
571 		if(offset < (ulong)end) {
572 			if(offset+n > (ulong)end)
573 				n = (ulong)end - offset;
574 			memmove(a, (char*)offset, n);
575 			return n;
576 		}
577 		/* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */
578 		if(offset >= conf.base0 && offset < conf.npage0){
579 			if(offset+n > conf.npage0)
580 				n = conf.npage0 - offset;
581 			memmove(a, (char*)offset, n);
582 			return n;
583 		}
584 		if(offset >= conf.base1 && offset < conf.npage1){
585 			if(offset+n > conf.npage1)
586 				n = conf.npage1 - offset;
587 			memmove(a, (char*)offset, n);
588 			return n;
589 		}
590 		error(Ebadarg);
591 
592 	case Qprofile:
593 		s = p->seg[TSEG];
594 		if(s == 0 || s->profile == 0)
595 			error("profile is off");
596 		i = (s->top-s->base)>>LRESPROF;
597 		i *= sizeof(*s->profile);
598 		if(offset >= i)
599 			return 0;
600 		if(offset+n > i)
601 			n = i - offset;
602 		memmove(a, ((char*)s->profile)+offset, n);
603 		return n;
604 
605 	case Qnote:
606 		qlock(&p->debug);
607 		if(waserror()){
608 			qunlock(&p->debug);
609 			nexterror();
610 		}
611 		if(p->pid != PID(c->qid))
612 			error(Eprocdied);
613 		if(n < 1)	/* must accept at least the '\0' */
614 			error(Etoosmall);
615 		if(p->nnote == 0)
616 			n = 0;
617 		else {
618 			m = strlen(p->note[0].msg) + 1;
619 			if(m > n)
620 				m = n;
621 			memmove(va, p->note[0].msg, m);
622 			((char*)va)[m-1] = '\0';
623 			p->nnote--;
624 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
625 			n = m;
626 		}
627 		if(p->nnote == 0)
628 			p->notepending = 0;
629 		poperror();
630 		qunlock(&p->debug);
631 		return n;
632 
633 	case Qproc:
634 		if(offset >= sizeof(Proc))
635 			return 0;
636 		if(offset+n > sizeof(Proc))
637 			n = sizeof(Proc) - offset;
638 		memmove(a, ((char*)p)+offset, n);
639 		return n;
640 
641 	case Qregs:
642 		rptr = (uchar*)p->dbgreg;
643 		rsize = sizeof(Ureg);
644 		goto regread;
645 
646 	case Qkregs:
647 		memset(&kur, 0, sizeof(Ureg));
648 		setkernur(&kur, p);
649 		rptr = (uchar*)&kur;
650 		rsize = sizeof(Ureg);
651 		goto regread;
652 
653 	case Qfpregs:
654 		rptr = (uchar*)&p->fpsave;
655 		rsize = sizeof(FPsave);
656 	regread:
657 		if(rptr == 0)
658 			error(Enoreg);
659 		if(offset >= rsize)
660 			return 0;
661 		if(offset+n > rsize)
662 			n = rsize - offset;
663 		memmove(a, rptr+offset, n);
664 		return n;
665 
666 	case Qstatus:
667 		if(offset >= STATSIZE)
668 			return 0;
669 		if(offset+n > STATSIZE)
670 			n = STATSIZE - offset;
671 
672 		sps = p->psstate;
673 		if(sps == 0)
674 			sps = statename[p->state];
675 		memset(statbuf, ' ', sizeof statbuf);
676 		memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
677 		memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
678 		memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
679 		j = 2*KNAMELEN + 12;
680 
681 		for(i = 0; i < 6; i++) {
682 			l = p->time[i];
683 			if(i == TReal)
684 				l = MACHP(0)->ticks - l;
685 			l = TK2MS(l);
686 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
687 		}
688 		/* ignore stack, which is mostly non-existent */
689 		l = 0;
690 		for(i=1; i<NSEG; i++){
691 			s = p->seg[i];
692 			if(s)
693 				l += s->top - s->base;
694 		}
695 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
696 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
697 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
698 		memmove(a, statbuf+offset, n);
699 		return n;
700 
701 	case Qsegment:
702 		j = 0;
703 		for(i = 0; i < NSEG; i++) {
704 			sg = p->seg[i];
705 			if(sg == 0)
706 				continue;
707 			j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
708 				sname[sg->type&SG_TYPE],
709 				sg->type&SG_RONLY ? 'R' : ' ',
710 				sg->profile ? 'P' : ' ',
711 				sg->base, sg->top, sg->ref);
712 		}
713 		if(offset >= j)
714 			return 0;
715 		if(offset+n > j)
716 			n = j-offset;
717 		if(n == 0 && offset == 0)
718 			exhausted("segments");
719 		memmove(a, &statbuf[offset], n);
720 		return n;
721 
722 	case Qwait:
723 		if(!canqlock(&p->qwaitr))
724 			error(Einuse);
725 
726 		if(waserror()) {
727 			qunlock(&p->qwaitr);
728 			nexterror();
729 		}
730 
731 		lock(&p->exl);
732 		if(up == p && p->nchild == 0 && p->waitq == 0) {
733 			unlock(&p->exl);
734 			error(Enochild);
735 		}
736 		pid = p->pid;
737 		while(p->waitq == 0) {
738 			unlock(&p->exl);
739 			sleep(&p->waitr, haswaitq, p);
740 			if(p->pid != pid)
741 				error(Eprocdied);
742 			lock(&p->exl);
743 		}
744 		wq = p->waitq;
745 		p->waitq = wq->next;
746 		p->nwait--;
747 		unlock(&p->exl);
748 
749 		qunlock(&p->qwaitr);
750 		poperror();
751 		n = snprint(a, n, "%d %lud %lud %lud %q",
752 			wq->w.pid,
753 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
754 			wq->w.msg);
755 		free(wq);
756 		return n;
757 
758 	case Qns:
759 		qlock(&p->debug);
760 		if(waserror()){
761 			qunlock(&p->debug);
762 			nexterror();
763 		}
764 		if(p->pgrp == nil || p->pid != PID(c->qid))
765 			error(Eprocdied);
766 		mw = c->aux;
767 		if(mw->cddone){
768 			qunlock(&p->debug);
769 			poperror();
770 			return 0;
771 		}
772 		mntscan(mw, p);
773 		if(mw->mh == 0){
774 			mw->cddone = 1;
775 			i = snprint(a, n, "cd %s\n", p->dot->name->s);
776 			qunlock(&p->debug);
777 			poperror();
778 			return i;
779 		}
780 		int2flag(mw->cm->mflag, flag);
781 		if(strcmp(mw->cm->to->name->s, "#M") == 0){
782 			srv = srvname(mw->cm->to->mchan);
783 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
784 				srv==nil? mw->cm->to->mchan->name->s : srv,
785 				mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : "");
786 			free(srv);
787 		}else
788 			i = snprint(a, n, "bind %s %s %s\n", flag,
789 				mw->cm->to->name->s, mw->mh->from->name->s);
790 		qunlock(&p->debug);
791 		poperror();
792 		return i;
793 
794 	case Qnoteid:
795 		return readnum(offset, va, n, p->noteid, NUMSIZE);
796 	case Qfd:
797 		return procfds(p, va, n, offset);
798 	}
799 	error(Egreg);
800 	return 0;		/* not reached */
801 }
802 
803 void
804 mntscan(Mntwalk *mw, Proc *p)
805 {
806 	Pgrp *pg;
807 	Mount *t;
808 	Mhead *f;
809 	int nxt, i;
810 	ulong last, bestmid;
811 
812 	pg = p->pgrp;
813 	rlock(&pg->ns);
814 
815 	nxt = 0;
816 	bestmid = ~0;
817 
818 	last = 0;
819 	if(mw->mh)
820 		last = mw->cm->mountid;
821 
822 	for(i = 0; i < MNTHASH; i++) {
823 		for(f = pg->mnthash[i]; f; f = f->hash) {
824 			for(t = f->mount; t; t = t->next) {
825 				if(mw->mh == 0 ||
826 				  (t->mountid > last && t->mountid < bestmid)) {
827 					mw->cm = t;
828 					mw->mh = f;
829 					bestmid = mw->cm->mountid;
830 					nxt = 1;
831 				}
832 			}
833 		}
834 	}
835 	if(nxt == 0)
836 		mw->mh = 0;
837 
838 	runlock(&pg->ns);
839 }
840 
841 static long
842 procwrite(Chan *c, void *va, long n, vlong off)
843 {
844 	int id, m;
845 	Proc *p, *t, *et;
846 	char *a, *arg, buf[ERRMAX];
847 	ulong offset = off;
848 
849 	a = va;
850 	if(c->qid.type & QTDIR)
851 		error(Eisdir);
852 
853 	p = proctab(SLOT(c->qid));
854 
855 	/* Use the remembered noteid in the channel rather
856 	 * than the process pgrpid
857 	 */
858 	if(QID(c->qid) == Qnotepg) {
859 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
860 		return n;
861 	}
862 
863 	qlock(&p->debug);
864 	if(waserror()){
865 		qunlock(&p->debug);
866 		nexterror();
867 	}
868 	if(p->pid != PID(c->qid))
869 		error(Eprocdied);
870 
871 	switch(QID(c->qid)){
872 	case Qargs:
873 		if(n == 0)
874 			error(Eshort);
875 		if(n >= ERRMAX)
876 			error(Etoobig);
877 		arg = malloc(n+1);
878 		if(arg == nil)
879 			error(Enomem);
880 		memmove(arg, va, n);
881 		m = n;
882 		if(arg[m-1] != 0)
883 			arg[m++] = 0;
884 		free(p->args);
885 		p->nargs = m;
886 		p->args = arg;
887 		p->setargs = 1;
888 		break;
889 
890 	case Qmem:
891 		if(p->state != Stopped)
892 			error(Ebadctl);
893 
894 		n = procctlmemio(p, offset, n, va, 0);
895 		break;
896 
897 	case Qregs:
898 		if(offset >= sizeof(Ureg))
899 			return 0;
900 		if(offset+n > sizeof(Ureg))
901 			n = sizeof(Ureg) - offset;
902 		if(p->dbgreg == 0)
903 			error(Enoreg);
904 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
905 		break;
906 
907 	case Qfpregs:
908 		if(offset >= sizeof(FPsave))
909 			return 0;
910 		if(offset+n > sizeof(FPsave))
911 			n = sizeof(FPsave) - offset;
912 		memmove((uchar*)&p->fpsave+offset, va, n);
913 		break;
914 
915 	case Qctl:
916 		procctlreq(p, va, n);
917 		break;
918 
919 	case Qnote:
920 		if(p->kp)
921 			error(Eperm);
922 		if(n >= ERRMAX-1)
923 			error(Etoobig);
924 		memmove(buf, va, n);
925 		buf[n] = 0;
926 		if(!postnote(p, 0, buf, NUser))
927 			error("note not posted");
928 		break;
929 	case Qnoteid:
930 		id = atoi(a);
931 		if(id == p->pid) {
932 			p->noteid = id;
933 			break;
934 		}
935 		t = proctab(0);
936 		for(et = t+conf.nproc; t < et; t++) {
937 			if(id == t->noteid) {
938 				if(strcmp(p->user, t->user) != 0)
939 					error(Eperm);
940 				p->noteid = id;
941 				break;
942 			}
943 		}
944 		if(p->noteid != id)
945 			error(Ebadarg);
946 		break;
947 	default:
948 		pprint("unknown qid in procwrite\n");
949 		error(Egreg);
950 	}
951 	poperror();
952 	qunlock(&p->debug);
953 	return n;
954 }
955 
956 Dev procdevtab = {
957 	'p',
958 	"proc",
959 
960 	devreset,
961 	procinit,
962 	devshutdown,
963 	procattach,
964 	procwalk,
965 	procstat,
966 	procopen,
967 	devcreate,
968 	procclose,
969 	procread,
970 	devbread,
971 	procwrite,
972 	devbwrite,
973 	devremove,
974 	procwstat,
975 };
976 
977 Chan*
978 proctext(Chan *c, Proc *p)
979 {
980 	Chan *tc;
981 	Image *i;
982 	Segment *s;
983 
984 	s = p->seg[TSEG];
985 	if(s == 0)
986 		error(Enonexist);
987 	if(p->state==Dead)
988 		error(Eprocdied);
989 
990 	lock(s);
991 	i = s->image;
992 	if(i == 0) {
993 		unlock(s);
994 		error(Eprocdied);
995 	}
996 	unlock(s);
997 
998 	lock(i);
999 	if(waserror()) {
1000 		unlock(i);
1001 		nexterror();
1002 	}
1003 
1004 	tc = i->c;
1005 	if(tc == 0)
1006 		error(Eprocdied);
1007 
1008 	if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1009 		cclose(tc);
1010 		error(Eprocdied);
1011 	}
1012 
1013 	if(p->pid != PID(c->qid))
1014 		error(Eprocdied);
1015 
1016 	unlock(i);
1017 	poperror();
1018 
1019 	return tc;
1020 }
1021 
1022 void
1023 procstopwait(Proc *p, int ctl)
1024 {
1025 	int pid;
1026 
1027 	if(p->pdbg)
1028 		error(Einuse);
1029 	if(procstopped(p) || p->state == Broken)
1030 		return;
1031 
1032 	if(ctl != 0)
1033 		p->procctl = ctl;
1034 	p->pdbg = up;
1035 	pid = p->pid;
1036 	qunlock(&p->debug);
1037 	up->psstate = "Stopwait";
1038 	if(waserror()) {
1039 		p->pdbg = 0;
1040 		qlock(&p->debug);
1041 		nexterror();
1042 	}
1043 	sleep(&up->sleep, procstopped, p);
1044 	poperror();
1045 	qlock(&p->debug);
1046 	if(p->pid != pid)
1047 		error(Eprocdied);
1048 }
1049 
1050 static void
1051 procctlcloseone(Proc *p, Fgrp *f, int fd)
1052 {
1053 	Chan *c;
1054 
1055 	c = f->fd[fd];
1056 	if(c == nil)
1057 		return;
1058 	f->fd[fd] = nil;
1059 	unlock(f);
1060 	qunlock(&p->debug);
1061 	cclose(c);
1062 	qlock(&p->debug);
1063 	lock(f);
1064 }
1065 
1066 void
1067 procctlclosefiles(Proc *p, int all, int fd)
1068 {
1069 	int i;
1070 	Fgrp *f;
1071 
1072 	f = p->fgrp;
1073 	if(f == nil)
1074 		error(Eprocdied);
1075 
1076 	lock(f);
1077 	f->ref++;
1078 	if(all)
1079 		for(i = 0; i < f->maxfd; i++)
1080 			procctlcloseone(p, f, i);
1081 	else
1082 		procctlcloseone(p, f, fd);
1083 	unlock(f);
1084 	closefgrp(f);
1085 }
1086 
1087 void
1088 procctlreq(Proc *p, char *va, int n)
1089 {
1090 	Segment *s;
1091 	int i, npc;
1092 	Cmdbuf *cb;
1093 	Cmdtab *ct;
1094 
1095 	if(p->kp)	/* no ctl requests to kprocs */
1096 		error(Eperm);
1097 
1098 	cb = parsecmd(va, n);
1099 	if(waserror()){
1100 		free(cb);
1101 		nexterror();
1102 	}
1103 
1104 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1105 
1106 	switch(ct->index){
1107 	case CMclose:
1108 		procctlclosefiles(p, 0, atoi(cb->f[1]));
1109 		break;
1110 	case CMclosefiles:
1111 		procctlclosefiles(p, 1, 0);
1112 		break;
1113 	case CMfixedpri:
1114 		i = atoi(cb->f[1]);
1115 		if(i < 0)
1116 			i = 0;
1117 		if(i >= Nrq)
1118 			i = Nrq - 1;
1119 		if(i > p->basepri && !iseve())
1120 			error(Eperm);
1121 		p->basepri = i;
1122 		p->fixedpri = 1;
1123 		break;
1124 	case CMhang:
1125 		p->hang = 1;
1126 		break;
1127 	case CMkill:
1128 		switch(p->state) {
1129 		case Broken:
1130 			unbreak(p);
1131 			break;
1132 		case Stopped:
1133 			postnote(p, 0, "sys: killed", NExit);
1134 			p->procctl = Proc_exitme;
1135 			ready(p);
1136 			break;
1137 		default:
1138 			postnote(p, 0, "sys: killed", NExit);
1139 			p->procctl = Proc_exitme;
1140 		}
1141 		break;
1142 	case CMnohang:
1143 		p->hang = 0;
1144 		break;
1145 	case CMnoswap:
1146 		p->noswap = 1;
1147 		break;
1148 	case CMpri:
1149 		i = atoi(cb->f[1]);
1150 		if(i < 0)
1151 			i = 0;
1152 		if(i >= Nrq)
1153 			i = Nrq - 1;
1154 		if(i > p->basepri && !iseve())
1155 			error(Eperm);
1156 		p->basepri = i;
1157 		p->fixedpri = 0;
1158 		break;
1159 	case CMprivate:
1160 		p->privatemem = 1;
1161 		break;
1162 	case CMprofile:
1163 		s = p->seg[TSEG];
1164 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1165 			error(Ebadctl);
1166 		if(s->profile != 0)
1167 			free(s->profile);
1168 		npc = (s->top-s->base)>>LRESPROF;
1169 		s->profile = malloc(npc*sizeof(*s->profile));
1170 		if(s->profile == 0)
1171 			error(Enomem);
1172 		break;
1173 	case CMstart:
1174 		if(p->state != Stopped)
1175 			error(Ebadctl);
1176 		ready(p);
1177 		break;
1178 	case CMstartstop:
1179 		if(p->state != Stopped)
1180 			error(Ebadctl);
1181 		p->procctl = Proc_traceme;
1182 		ready(p);
1183 		procstopwait(p, Proc_traceme);
1184 		break;
1185 	case CMstop:
1186 		procstopwait(p, Proc_stopme);
1187 		break;
1188 	case CMwaitstop:
1189 		procstopwait(p, 0);
1190 		break;
1191 	case CMwired:
1192 		procwired(p, atoi(cb->f[1]));
1193 		break;
1194 	}
1195 
1196 	poperror();
1197 	free(cb);
1198 }
1199 
1200 int
1201 procstopped(void *a)
1202 {
1203 	Proc *p = a;
1204 	return p->state == Stopped;
1205 }
1206 
1207 int
1208 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1209 {
1210 	KMap *k;
1211 	Pte *pte;
1212 	Page *pg;
1213 	Segment *s;
1214 	ulong soff, l;
1215 	char *a = va, *b;
1216 
1217 	for(;;) {
1218 		s = seg(p, offset, 1);
1219 		if(s == 0)
1220 			error(Ebadarg);
1221 
1222 		if(offset+n >= s->top)
1223 			n = s->top-offset;
1224 
1225 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1226 			s = txt2data(p, s);
1227 
1228 		s->steal++;
1229 		soff = offset-s->base;
1230 		if(waserror()) {
1231 			s->steal--;
1232 			nexterror();
1233 		}
1234 		if(fixfault(s, offset, read, 0) == 0)
1235 			break;
1236 		poperror();
1237 		s->steal--;
1238 	}
1239 	poperror();
1240 	pte = s->map[soff/PTEMAPMEM];
1241 	if(pte == 0)
1242 		panic("procctlmemio");
1243 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1244 	if(pagedout(pg))
1245 		panic("procctlmemio1");
1246 
1247 	l = BY2PG - (offset&(BY2PG-1));
1248 	if(n > l)
1249 		n = l;
1250 
1251 	k = kmap(pg);
1252 	if(waserror()) {
1253 		s->steal--;
1254 		kunmap(k);
1255 		nexterror();
1256 	}
1257 	b = (char*)VA(k);
1258 	b += offset&(BY2PG-1);
1259 	if(read == 1)
1260 		memmove(a, b, n);	/* This can fault */
1261 	else
1262 		memmove(b, a, n);
1263 	kunmap(k);
1264 	poperror();
1265 
1266 	/* Ensure the process sees text page changes */
1267 	if(s->flushme)
1268 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1269 
1270 	s->steal--;
1271 
1272 	if(read == 0)
1273 		p->newtlb = 1;
1274 
1275 	return n;
1276 }
1277 
1278 Segment*
1279 txt2data(Proc *p, Segment *s)
1280 {
1281 	int i;
1282 	Segment *ps;
1283 
1284 	ps = newseg(SG_DATA, s->base, s->size);
1285 	ps->image = s->image;
1286 	incref(ps->image);
1287 	ps->fstart = s->fstart;
1288 	ps->flen = s->flen;
1289 	ps->flushme = 1;
1290 
1291 	qlock(&p->seglock);
1292 	for(i = 0; i < NSEG; i++)
1293 		if(p->seg[i] == s)
1294 			break;
1295 	if(p->seg[i] != s)
1296 		panic("segment gone");
1297 
1298 	qunlock(&s->lk);
1299 	putseg(s);
1300 	qlock(&ps->lk);
1301 	p->seg[i] = ps;
1302 	qunlock(&p->seglock);
1303 
1304 	return ps;
1305 }
1306 
1307 Segment*
1308 data2txt(Segment *s)
1309 {
1310 	Segment *ps;
1311 
1312 	ps = newseg(SG_TEXT, s->base, s->size);
1313 	ps->image = s->image;
1314 	incref(ps->image);
1315 	ps->fstart = s->fstart;
1316 	ps->flen = s->flen;
1317 	ps->flushme = 1;
1318 
1319 	return ps;
1320 }
1321