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