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