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