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