vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

devproc.c (25824B)


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