xref: /plan9/sys/src/9/port/devproc.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
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 	/* NSEG*32 was too small for worst cases */
675 	char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
676 	int i, j, m, navail, ne, pid, rsize;
677 	long l;
678 	uchar *rptr;
679 	ulong offset;
680 	Confmem *cm;
681 	Mntwalk *mw;
682 	Proc *p;
683 	Segment *sg, *s;
684 	Ureg kur;
685 	Waitq *wq;
686 
687 	a = va;
688 	offset = off;
689 
690 	if(c->qid.type & QTDIR)
691 		return devdirread(c, a, n, 0, 0, procgen);
692 
693 	if(QID(c->qid) == Qtrace){
694 		if(!eventsavailable(nil))
695 			return 0;
696 
697 		rptr = (uchar*)va;
698 		navail = tproduced - tconsumed;
699 		if(navail > n / sizeof(Traceevent))
700 			navail = n / sizeof(Traceevent);
701 		while(navail > 0) {
702 			ne = ((tconsumed & Emask) + navail > Nevents)?
703 					Nevents - (tconsumed & Emask): navail;
704 			memmove(rptr, &tevents[tconsumed & Emask],
705 					ne * sizeof(Traceevent));
706 
707 			tconsumed += ne;
708 			rptr += ne * sizeof(Traceevent);
709 			navail -= ne;
710 		}
711 		return rptr - (uchar*)va;
712 	}
713 
714 	p = proctab(SLOT(c->qid));
715 	if(p->pid != PID(c->qid))
716 		error(Eprocdied);
717 
718 	switch(QID(c->qid)){
719 	case Qargs:
720 		qlock(&p->debug);
721 		j = procargs(p, p->genbuf, sizeof p->genbuf);
722 		qunlock(&p->debug);
723 		if(offset >= j)
724 			return 0;
725 		if(offset+n > j)
726 			n = j-offset;
727 		memmove(a, &p->genbuf[offset], n);
728 		return n;
729 
730 	case Qmem:
731 		if(offset < KZERO)
732 			return procctlmemio(p, offset, n, va, 1);
733 
734 		if(!iseve())
735 			error(Eperm);
736 
737 		/* validate kernel addresses */
738 		if(offset < (ulong)end) {
739 			if(offset+n > (ulong)end)
740 				n = (ulong)end - offset;
741 			memmove(a, (char*)offset, n);
742 			return n;
743 		}
744 		for(i=0; i<nelem(conf.mem); i++){
745 			cm = &conf.mem[i];
746 			/* klimit-1 because klimit might be zero! */
747 			if(cm->kbase <= offset && offset <= cm->klimit-1){
748 				if(offset+n >= cm->klimit-1)
749 					n = cm->klimit - offset;
750 				memmove(a, (char*)offset, n);
751 				return n;
752 			}
753 		}
754 		error(Ebadarg);
755 
756 	case Qprofile:
757 		s = p->seg[TSEG];
758 		if(s == 0 || s->profile == 0)
759 			error("profile is off");
760 		i = (s->top-s->base)>>LRESPROF;
761 		i *= sizeof(*s->profile);
762 		if(offset >= i)
763 			return 0;
764 		if(offset+n > i)
765 			n = i - offset;
766 		memmove(a, ((char*)s->profile)+offset, n);
767 		return n;
768 
769 	case Qnote:
770 		qlock(&p->debug);
771 		if(waserror()){
772 			qunlock(&p->debug);
773 			nexterror();
774 		}
775 		if(p->pid != PID(c->qid))
776 			error(Eprocdied);
777 		if(n < 1)	/* must accept at least the '\0' */
778 			error(Etoosmall);
779 		if(p->nnote == 0)
780 			n = 0;
781 		else {
782 			m = strlen(p->note[0].msg) + 1;
783 			if(m > n)
784 				m = n;
785 			memmove(va, p->note[0].msg, m);
786 			((char*)va)[m-1] = '\0';
787 			p->nnote--;
788 			memmove(p->note, p->note+1, p->nnote*sizeof(Note));
789 			n = m;
790 		}
791 		if(p->nnote == 0)
792 			p->notepending = 0;
793 		poperror();
794 		qunlock(&p->debug);
795 		return n;
796 
797 	case Qproc:
798 		if(offset >= sizeof(Proc))
799 			return 0;
800 		if(offset+n > sizeof(Proc))
801 			n = sizeof(Proc) - offset;
802 		memmove(a, ((char*)p)+offset, n);
803 		return n;
804 
805 	case Qregs:
806 		rptr = (uchar*)p->dbgreg;
807 		rsize = sizeof(Ureg);
808 		goto regread;
809 
810 	case Qkregs:
811 		memset(&kur, 0, sizeof(Ureg));
812 		setkernur(&kur, p);
813 		rptr = (uchar*)&kur;
814 		rsize = sizeof(Ureg);
815 		goto regread;
816 
817 	case Qfpregs:
818 		rptr = (uchar*)&p->fpsave;
819 		rsize = sizeof(FPsave);
820 	regread:
821 		if(rptr == 0)
822 			error(Enoreg);
823 		if(offset >= rsize)
824 			return 0;
825 		if(offset+n > rsize)
826 			n = rsize - offset;
827 		memmove(a, rptr+offset, n);
828 		return n;
829 
830 	case Qstatus:
831 		if(offset >= STATSIZE)
832 			return 0;
833 		if(offset+n > STATSIZE)
834 			n = STATSIZE - offset;
835 
836 		sps = p->psstate;
837 		if(sps == 0)
838 			sps = statename[p->state];
839 		memset(statbuf, ' ', sizeof statbuf);
840 		memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
841 		memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
842 		memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
843 		j = 2*KNAMELEN + 12;
844 
845 		for(i = 0; i < 6; i++) {
846 			l = p->time[i];
847 			if(i == TReal)
848 				l = MACHP(0)->ticks - l;
849 			l = TK2MS(l);
850 			readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
851 		}
852 		/* ignore stack, which is mostly non-existent */
853 		l = 0;
854 		for(i=1; i<NSEG; i++){
855 			s = p->seg[i];
856 			if(s)
857 				l += s->top - s->base;
858 		}
859 		readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
860 		readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
861 		readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
862 		memmove(a, statbuf+offset, n);
863 		return n;
864 
865 	case Qsegment:
866 		j = 0;
867 		for(i = 0; i < NSEG; i++) {
868 			sg = p->seg[i];
869 			if(sg == 0)
870 				continue;
871 			j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
872 				sname[sg->type&SG_TYPE],
873 				sg->type&SG_RONLY ? 'R' : ' ',
874 				sg->profile ? 'P' : ' ',
875 				sg->base, sg->top, sg->ref);
876 		}
877 		if(offset >= j)
878 			return 0;
879 		if(offset+n > j)
880 			n = j-offset;
881 		if(n == 0 && offset == 0)
882 			exhausted("segments");
883 		memmove(a, &statbuf[offset], n);
884 		return n;
885 
886 	case Qwait:
887 		if(!canqlock(&p->qwaitr))
888 			error(Einuse);
889 
890 		if(waserror()) {
891 			qunlock(&p->qwaitr);
892 			nexterror();
893 		}
894 
895 		lock(&p->exl);
896 		if(up == p && p->nchild == 0 && p->waitq == 0) {
897 			unlock(&p->exl);
898 			error(Enochild);
899 		}
900 		pid = p->pid;
901 		while(p->waitq == 0) {
902 			unlock(&p->exl);
903 			sleep(&p->waitr, haswaitq, p);
904 			if(p->pid != pid)
905 				error(Eprocdied);
906 			lock(&p->exl);
907 		}
908 		wq = p->waitq;
909 		p->waitq = wq->next;
910 		p->nwait--;
911 		unlock(&p->exl);
912 
913 		qunlock(&p->qwaitr);
914 		poperror();
915 		n = snprint(a, n, "%d %lud %lud %lud %q",
916 			wq->w.pid,
917 			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
918 			wq->w.msg);
919 		free(wq);
920 		return n;
921 
922 	case Qns:
923 		qlock(&p->debug);
924 		if(waserror()){
925 			qunlock(&p->debug);
926 			nexterror();
927 		}
928 		if(p->pgrp == nil || p->pid != PID(c->qid))
929 			error(Eprocdied);
930 		mw = c->aux;
931 		if(mw->cddone){
932 			qunlock(&p->debug);
933 			poperror();
934 			return 0;
935 		}
936 		mntscan(mw, p);
937 		if(mw->mh == 0){
938 			mw->cddone = 1;
939 			i = snprint(a, n, "cd %s\n", p->dot->path->s);
940 			qunlock(&p->debug);
941 			poperror();
942 			return i;
943 		}
944 		int2flag(mw->cm->mflag, flag);
945 		if(strcmp(mw->cm->to->path->s, "#M") == 0){
946 			srv = srvname(mw->cm->to->mchan);
947 			i = snprint(a, n, "mount %s %s %s %s\n", flag,
948 				srv==nil? mw->cm->to->mchan->path->s : srv,
949 				mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
950 			free(srv);
951 		}else
952 			i = snprint(a, n, "bind %s %s %s\n", flag,
953 				mw->cm->to->path->s, mw->mh->from->path->s);
954 		qunlock(&p->debug);
955 		poperror();
956 		return i;
957 
958 	case Qnoteid:
959 		return readnum(offset, va, n, p->noteid, NUMSIZE);
960 	case Qfd:
961 		return procfds(p, va, n, offset);
962 	}
963 	error(Egreg);
964 	return 0;		/* not reached */
965 }
966 
967 void
968 mntscan(Mntwalk *mw, Proc *p)
969 {
970 	Pgrp *pg;
971 	Mount *t;
972 	Mhead *f;
973 	int nxt, i;
974 	ulong last, bestmid;
975 
976 	pg = p->pgrp;
977 	rlock(&pg->ns);
978 
979 	nxt = 0;
980 	bestmid = ~0;
981 
982 	last = 0;
983 	if(mw->mh)
984 		last = mw->cm->mountid;
985 
986 	for(i = 0; i < MNTHASH; i++) {
987 		for(f = pg->mnthash[i]; f; f = f->hash) {
988 			for(t = f->mount; t; t = t->next) {
989 				if(mw->mh == 0 ||
990 				  (t->mountid > last && t->mountid < bestmid)) {
991 					mw->cm = t;
992 					mw->mh = f;
993 					bestmid = mw->cm->mountid;
994 					nxt = 1;
995 				}
996 			}
997 		}
998 	}
999 	if(nxt == 0)
1000 		mw->mh = 0;
1001 
1002 	runlock(&pg->ns);
1003 }
1004 
1005 static long
1006 procwrite(Chan *c, void *va, long n, vlong off)
1007 {
1008 	int id, m;
1009 	Proc *p, *t, *et;
1010 	char *a, *arg, buf[ERRMAX];
1011 	ulong offset = off;
1012 
1013 	a = va;
1014 	if(c->qid.type & QTDIR)
1015 		error(Eisdir);
1016 
1017 	p = proctab(SLOT(c->qid));
1018 
1019 	/* Use the remembered noteid in the channel rather
1020 	 * than the process pgrpid
1021 	 */
1022 	if(QID(c->qid) == Qnotepg) {
1023 		pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1024 		return n;
1025 	}
1026 
1027 	qlock(&p->debug);
1028 	if(waserror()){
1029 		qunlock(&p->debug);
1030 		nexterror();
1031 	}
1032 	if(p->pid != PID(c->qid))
1033 		error(Eprocdied);
1034 
1035 	switch(QID(c->qid)){
1036 	case Qargs:
1037 		if(n == 0)
1038 			error(Eshort);
1039 		if(n >= ERRMAX)
1040 			error(Etoobig);
1041 		arg = malloc(n+1);
1042 		if(arg == nil)
1043 			error(Enomem);
1044 		memmove(arg, va, n);
1045 		m = n;
1046 		if(arg[m-1] != 0)
1047 			arg[m++] = 0;
1048 		free(p->args);
1049 		p->nargs = m;
1050 		p->args = arg;
1051 		p->setargs = 1;
1052 		break;
1053 
1054 	case Qmem:
1055 		if(p->state != Stopped)
1056 			error(Ebadctl);
1057 
1058 		n = procctlmemio(p, offset, n, va, 0);
1059 		break;
1060 
1061 	case Qregs:
1062 		if(offset >= sizeof(Ureg))
1063 			return 0;
1064 		if(offset+n > sizeof(Ureg))
1065 			n = sizeof(Ureg) - offset;
1066 		if(p->dbgreg == 0)
1067 			error(Enoreg);
1068 		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1069 		break;
1070 
1071 	case Qfpregs:
1072 		if(offset >= sizeof(FPsave))
1073 			return 0;
1074 		if(offset+n > sizeof(FPsave))
1075 			n = sizeof(FPsave) - offset;
1076 		memmove((uchar*)&p->fpsave+offset, va, n);
1077 		break;
1078 
1079 	case Qctl:
1080 		procctlreq(p, va, n);
1081 		break;
1082 
1083 	case Qnote:
1084 		if(p->kp)
1085 			error(Eperm);
1086 		if(n >= ERRMAX-1)
1087 			error(Etoobig);
1088 		memmove(buf, va, n);
1089 		buf[n] = 0;
1090 		if(!postnote(p, 0, buf, NUser))
1091 			error("note not posted");
1092 		break;
1093 	case Qnoteid:
1094 		id = atoi(a);
1095 		if(id == p->pid) {
1096 			p->noteid = id;
1097 			break;
1098 		}
1099 		t = proctab(0);
1100 		for(et = t+conf.nproc; t < et; t++) {
1101 			if(t->state == Dead)
1102 				continue;
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 	void (*pt)(Proc*, int, vlong);
1296 
1297 	if(p->kp)	/* no ctl requests to kprocs */
1298 		error(Eperm);
1299 
1300 	cb = parsecmd(va, n);
1301 	if(waserror()){
1302 		free(cb);
1303 		nexterror();
1304 	}
1305 
1306 	ct = lookupcmd(cb, proccmd, nelem(proccmd));
1307 
1308 	switch(ct->index){
1309 	case CMclose:
1310 		procctlclosefiles(p, 0, atoi(cb->f[1]));
1311 		break;
1312 	case CMclosefiles:
1313 		procctlclosefiles(p, 1, 0);
1314 		break;
1315 	case CMhang:
1316 		p->hang = 1;
1317 		break;
1318 	case CMkill:
1319 		switch(p->state) {
1320 		case Broken:
1321 			unbreak(p);
1322 			break;
1323 		case Stopped:
1324 			p->procctl = Proc_exitme;
1325 			postnote(p, 0, "sys: killed", NExit);
1326 			ready(p);
1327 			break;
1328 		default:
1329 			p->procctl = Proc_exitme;
1330 			postnote(p, 0, "sys: killed", NExit);
1331 		}
1332 		break;
1333 	case CMnohang:
1334 		p->hang = 0;
1335 		break;
1336 	case CMnoswap:
1337 		p->noswap = 1;
1338 		break;
1339 	case CMpri:
1340 		pri = atoi(cb->f[1]);
1341 		if(pri > PriNormal && !iseve())
1342 			error(Eperm);
1343 		procpriority(p, pri, 0);
1344 		break;
1345 	case CMfixedpri:
1346 		pri = atoi(cb->f[1]);
1347 		if(pri > PriNormal && !iseve())
1348 			error(Eperm);
1349 		procpriority(p, pri, 1);
1350 		break;
1351 	case CMprivate:
1352 		p->privatemem = 1;
1353 		break;
1354 	case CMprofile:
1355 		s = p->seg[TSEG];
1356 		if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1357 			error(Ebadctl);
1358 		if(s->profile != 0)
1359 			free(s->profile);
1360 		npc = (s->top-s->base)>>LRESPROF;
1361 		s->profile = malloc(npc*sizeof(*s->profile));
1362 		if(s->profile == 0)
1363 			error(Enomem);
1364 		break;
1365 	case CMstart:
1366 		if(p->state != Stopped)
1367 			error(Ebadctl);
1368 		ready(p);
1369 		break;
1370 	case CMstartstop:
1371 		if(p->state != Stopped)
1372 			error(Ebadctl);
1373 		p->procctl = Proc_traceme;
1374 		ready(p);
1375 		procstopwait(p, Proc_traceme);
1376 		break;
1377 	case CMstartsyscall:
1378 		if(p->state != Stopped)
1379 			error(Ebadctl);
1380 		p->procctl = Proc_tracesyscall;
1381 		ready(p);
1382 		procstopwait(p, Proc_tracesyscall);
1383 		break;
1384 	case CMstop:
1385 		procstopwait(p, Proc_stopme);
1386 		break;
1387 	case CMwaitstop:
1388 		procstopwait(p, 0);
1389 		break;
1390 	case CMwired:
1391 		procwired(p, atoi(cb->f[1]));
1392 		break;
1393 	case CMtrace:
1394 		switch(cb->nf){
1395 		case 1:
1396 			p->trace ^= 1;
1397 			break;
1398 		case 2:
1399 			p->trace = (atoi(cb->f[1]) != 0);
1400 			break;
1401 		default:
1402 			error("args");
1403 		}
1404 		break;
1405 	/* real time */
1406 	case CMperiod:
1407 		if(p->edf == nil)
1408 			edfinit(p);
1409 		if(e=parsetime(&time, cb->f[1]))	/* time in ns */
1410 			error(e);
1411 		edfstop(p);
1412 		p->edf->T = time/1000;	/* Edf times are in µs */
1413 		break;
1414 	case CMdeadline:
1415 		if(p->edf == nil)
1416 			edfinit(p);
1417 		if(e=parsetime(&time, cb->f[1]))
1418 			error(e);
1419 		edfstop(p);
1420 		p->edf->D = time/1000;
1421 		break;
1422 	case CMcost:
1423 		if(p->edf == nil)
1424 			edfinit(p);
1425 		if(e=parsetime(&time, cb->f[1]))
1426 			error(e);
1427 		edfstop(p);
1428 		p->edf->C = time/1000;
1429 		break;
1430 	case CMsporadic:
1431 		if(p->edf == nil)
1432 			edfinit(p);
1433 		p->edf->flags |= Sporadic;
1434 		break;
1435 	case CMdeadlinenotes:
1436 		if(p->edf == nil)
1437 			edfinit(p);
1438 		p->edf->flags |= Sendnotes;
1439 		break;
1440 	case CMadmit:
1441 		if(p->edf == 0)
1442 			error("edf params");
1443 		if(e = edfadmit(p))
1444 			error(e);
1445 		break;
1446 	case CMextra:
1447 		if(p->edf == nil)
1448 			edfinit(p);
1449 		p->edf->flags |= Extratime;
1450 		break;
1451 	case CMexpel:
1452 		if(p->edf)
1453 			edfstop(p);
1454 		break;
1455 	case CMevent:
1456 		pt = proctrace;
1457 		if(up->trace && pt)
1458 			pt(up, SUser, 0);
1459 		break;
1460 	}
1461 
1462 	poperror();
1463 	free(cb);
1464 }
1465 
1466 int
1467 procstopped(void *a)
1468 {
1469 	Proc *p = a;
1470 	return p->state == Stopped;
1471 }
1472 
1473 int
1474 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1475 {
1476 	KMap *k;
1477 	Pte *pte;
1478 	Page *pg;
1479 	Segment *s;
1480 	ulong soff, l;
1481 	char *a = va, *b;
1482 
1483 	for(;;) {
1484 		s = seg(p, offset, 1);
1485 		if(s == 0)
1486 			error(Ebadarg);
1487 
1488 		if(offset+n >= s->top)
1489 			n = s->top-offset;
1490 
1491 		if(!read && (s->type&SG_TYPE) == SG_TEXT)
1492 			s = txt2data(p, s);
1493 
1494 		s->steal++;
1495 		soff = offset-s->base;
1496 		if(waserror()) {
1497 			s->steal--;
1498 			nexterror();
1499 		}
1500 		if(fixfault(s, offset, read, 0) == 0)
1501 			break;
1502 		poperror();
1503 		s->steal--;
1504 	}
1505 	poperror();
1506 	pte = s->map[soff/PTEMAPMEM];
1507 	if(pte == 0)
1508 		panic("procctlmemio");
1509 	pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1510 	if(pagedout(pg))
1511 		panic("procctlmemio1");
1512 
1513 	l = BY2PG - (offset&(BY2PG-1));
1514 	if(n > l)
1515 		n = l;
1516 
1517 	k = kmap(pg);
1518 	if(waserror()) {
1519 		s->steal--;
1520 		kunmap(k);
1521 		nexterror();
1522 	}
1523 	b = (char*)VA(k);
1524 	b += offset&(BY2PG-1);
1525 	if(read == 1)
1526 		memmove(a, b, n);	/* This can fault */
1527 	else
1528 		memmove(b, a, n);
1529 	kunmap(k);
1530 	poperror();
1531 
1532 	/* Ensure the process sees text page changes */
1533 	if(s->flushme)
1534 		memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1535 
1536 	s->steal--;
1537 
1538 	if(read == 0)
1539 		p->newtlb = 1;
1540 
1541 	return n;
1542 }
1543 
1544 Segment*
1545 txt2data(Proc *p, Segment *s)
1546 {
1547 	int i;
1548 	Segment *ps;
1549 
1550 	ps = newseg(SG_DATA, s->base, s->size);
1551 	ps->image = s->image;
1552 	incref(ps->image);
1553 	ps->fstart = s->fstart;
1554 	ps->flen = s->flen;
1555 	ps->flushme = 1;
1556 
1557 	qlock(&p->seglock);
1558 	for(i = 0; i < NSEG; i++)
1559 		if(p->seg[i] == s)
1560 			break;
1561 	if(p->seg[i] != s)
1562 		panic("segment gone");
1563 
1564 	qunlock(&s->lk);
1565 	putseg(s);
1566 	qlock(&ps->lk);
1567 	p->seg[i] = ps;
1568 	qunlock(&p->seglock);
1569 
1570 	return ps;
1571 }
1572 
1573 Segment*
1574 data2txt(Segment *s)
1575 {
1576 	Segment *ps;
1577 
1578 	ps = newseg(SG_TEXT, s->base, s->size);
1579 	ps->image = s->image;
1580 	incref(ps->image);
1581 	ps->fstart = s->fstart;
1582 	ps->flen = s->flen;
1583 	ps->flushme = 1;
1584 
1585 	return ps;
1586 }
1587