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