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