]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devproc.c
etheriwl: add /lib/firmware to bootfs.paq proto file
[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                         unlock(&tlock);
355                         nexterror();
356                 }
357                 if (topens > 0)
358                         error("already open");
359                 topens++;
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){
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){
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 }
629
630 static void
631 int2flag(int flag, char *s)
632 {
633         if(flag == 0){
634                 *s = '\0';
635                 return;
636         }
637         *s++ = '-';
638         if(flag & MAFTER)
639                 *s++ = 'a';
640         if(flag & MBEFORE)
641                 *s++ = 'b';
642         if(flag & MCREATE)
643                 *s++ = 'c';
644         if(flag & MCACHE)
645                 *s++ = 'C';
646         *s = '\0';
647 }
648
649 static int
650 procargs(Proc *p, char *buf, int nbuf)
651 {
652         int j, k, m;
653         char *a;
654         int n;
655
656         a = p->args;
657         if(p->setargs){
658                 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
659                 return strlen(buf);
660         }
661         n = p->nargs;
662         for(j = 0; j < nbuf - 1; j += m){
663                 if(n <= 0)
664                         break;
665                 if(j != 0)
666                         buf[j++] = ' ';
667                 m = snprint(buf+j, nbuf-j, "%q",  a);
668                 k = strlen(a) + 1;
669                 a += k;
670                 n -= k;
671         }
672         return j;
673 }
674
675 static int
676 eventsavailable(void *)
677 {
678         return tproduced > tconsumed;
679 }
680
681 static long
682 procread(Chan *c, void *va, long n, vlong off)
683 {
684         /* NSEG*32 was too small for worst cases */
685         char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
686         int i, j, m, navail, ne, pid, rsize;
687         long l;
688         uchar *rptr;
689         ulong offset;
690         Confmem *cm;
691         Mntwalk *mw;
692         Proc *p;
693         Segment *sg, *s;
694         Ureg kur;
695         Waitq *wq;
696         
697         a = va;
698         offset = off;
699
700         if(c->qid.type & QTDIR)
701                 return devdirread(c, a, n, 0, 0, procgen);
702
703         if(QID(c->qid) == Qtrace){
704                 if(!eventsavailable(nil))
705                         return 0;
706
707                 rptr = (uchar*)va;
708                 navail = tproduced - tconsumed;
709                 if(navail > n / sizeof(Traceevent))
710                         navail = n / sizeof(Traceevent);
711                 while(navail > 0) {
712                         ne = ((tconsumed & Emask) + navail > Nevents)? 
713                                         Nevents - (tconsumed & Emask): navail;
714                         memmove(rptr, &tevents[tconsumed & Emask], 
715                                         ne * sizeof(Traceevent));
716
717                         tconsumed += ne;
718                         rptr += ne * sizeof(Traceevent);
719                         navail -= ne;
720                 }
721                 return rptr - (uchar*)va;
722         }
723
724         p = proctab(SLOT(c->qid));
725         if(p->pid != PID(c->qid))
726                 error(Eprocdied);
727
728         switch(QID(c->qid)){
729         case Qargs:
730                 eqlock(&p->debug);
731                 j = procargs(p, up->genbuf, sizeof up->genbuf);
732                 qunlock(&p->debug);
733                 if(offset >= j)
734                         return 0;
735                 if(offset+n > j)
736                         n = j-offset;
737                 memmove(a, &up->genbuf[offset], n);
738                 return n;
739         case Qsyscall:
740                 eqlock(&p->debug);
741                 if(p->syscalltrace)
742                         n = readstr(offset, a, n, p->syscalltrace);
743                 else
744                         n = 0;
745                 qunlock(&p->debug);
746                 return n;
747
748         case Qmem:
749                 if(offset < KZERO)
750                         return procctlmemio(p, offset, n, va, 1);
751
752                 if(!iseve())
753                         error(Eperm);
754
755                 /* validate kernel addresses */
756                 if(offset < (ulong)end) {
757                         if(offset+n > (ulong)end)
758                                 n = (ulong)end - offset;
759                         memmove(a, (char*)offset, n);
760                         return n;
761                 }
762                 for(i=0; i<nelem(conf.mem); i++){
763                         cm = &conf.mem[i];
764                         /* klimit-1 because klimit might be zero! */
765                         if(cm->kbase <= offset && offset <= cm->klimit-1){
766                                 if(offset+n >= cm->klimit-1)
767                                         n = cm->klimit - offset;
768                                 memmove(a, (char*)offset, n);
769                                 return n;
770                         }
771                 }
772                 error(Ebadarg);
773
774         case Qprofile:
775                 s = p->seg[TSEG];
776                 if(s == 0 || s->profile == 0)
777                         error("profile is off");
778                 i = (s->top-s->base)>>LRESPROF;
779                 i *= sizeof(*s->profile);
780                 if(offset >= i)
781                         return 0;
782                 if(offset+n > i)
783                         n = i - offset;
784                 memmove(a, ((char*)s->profile)+offset, n);
785                 return n;
786
787         case Qnote:
788                 eqlock(&p->debug);
789                 if(waserror()){
790                         qunlock(&p->debug);
791                         nexterror();
792                 }
793                 if(p->pid != PID(c->qid))
794                         error(Eprocdied);
795                 if(n < 1)       /* must accept at least the '\0' */
796                         error(Etoosmall);
797                 if(p->nnote == 0)
798                         n = 0;
799                 else {
800                         m = strlen(p->note[0].msg) + 1;
801                         if(m > n)
802                                 m = n;
803                         memmove(va, p->note[0].msg, m-1);
804                         ((char*)va)[m-1] = '\0';
805                         p->nnote--;
806                         memmove(p->note, p->note+1, p->nnote*sizeof(Note));
807                         n = m;
808                 }
809                 if(p->nnote == 0)
810                         p->notepending = 0;
811                 poperror();
812                 qunlock(&p->debug);
813                 return n;
814
815         case Qproc:
816                 if(offset >= sizeof(Proc))
817                         return 0;
818                 if(offset+n > sizeof(Proc))
819                         n = sizeof(Proc) - offset;
820                 memmove(a, ((char*)p)+offset, n);
821                 return n;
822
823         case Qregs:
824                 rptr = (uchar*)p->dbgreg;
825                 rsize = sizeof(Ureg);
826                 goto regread;
827
828         case Qkregs:
829                 memset(&kur, 0, sizeof(Ureg));
830                 setkernur(&kur, p);
831                 rptr = (uchar*)&kur;
832                 rsize = sizeof(Ureg);
833                 goto regread;
834
835         case Qfpregs:
836                 rptr = (uchar*)&p->fpsave;
837                 rsize = sizeof(FPsave);
838         regread:
839                 if(rptr == 0)
840                         error(Enoreg);
841                 if(offset >= rsize)
842                         return 0;
843                 if(offset+n > rsize)
844                         n = rsize - offset;
845                 memmove(a, rptr+offset, n);
846                 return n;
847
848         case Qstatus:
849                 if(offset >= STATSIZE)
850                         return 0;
851                 if(offset+n > STATSIZE)
852                         n = STATSIZE - offset;
853
854                 sps = p->psstate;
855                 if(sps == 0)
856                         sps = statename[p->state];
857
858                 memset(statbuf, ' ', sizeof statbuf);
859                 readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
860                 readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
861                 readstr(0, statbuf+2*KNAMELEN, 11, sps);
862
863                 j = 2*KNAMELEN + 12;
864                 for(i = 0; i < 6; i++) {
865                         l = p->time[i];
866                         if(i == TReal)
867                                 l = MACHP(0)->ticks - l;
868                         l = TK2MS(l);
869                         readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
870                 }
871
872                 l = 0;
873                 eqlock(&p->seglock);
874                 if(waserror()){
875                         qunlock(&p->seglock);
876                         nexterror();
877                 }
878                 for(i=0; i<NSEG; i++){
879                         if(s = p->seg[i]){
880                                 eqlock(&s->lk);
881                                 l += mcountseg(s);
882                                 qunlock(&s->lk);
883                         }
884                 }
885                 poperror();
886                 qunlock(&p->seglock);
887
888                 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l*BY2PG/1024, NUMSIZE);
889                 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
890                 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
891                 memmove(a, statbuf+offset, n);
892                 return n;
893
894         case Qsegment:
895                 j = 0;
896                 for(i = 0; i < NSEG; i++) {
897                         sg = p->seg[i];
898                         if(sg == 0)
899                                 continue;
900                         j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
901                                 sname[sg->type&SG_TYPE],
902                                 sg->type&SG_RONLY ? 'R' : ' ',
903                                 sg->profile ? 'P' : ' ',
904                                 sg->base, sg->top, sg->ref);
905                 }
906                 if(offset >= j)
907                         return 0;
908                 if(offset+n > j)
909                         n = j-offset;
910                 if(n == 0 && offset == 0)
911                         exhausted("segments");
912                 memmove(a, &statbuf[offset], n);
913                 return n;
914
915         case Qwait:
916                 if(!canqlock(&p->qwaitr))
917                         error(Einuse);
918
919                 if(waserror()) {
920                         qunlock(&p->qwaitr);
921                         nexterror();
922                 }
923
924                 lock(&p->exl);
925                 pid = p->pid;
926                 while(p->waitq == 0) {
927                         if(up == p && p->nchild == 0) {
928                                 unlock(&p->exl);
929                                 error(Enochild);
930                         }
931                         unlock(&p->exl);
932                         sleep(&p->waitr, haswaitq, p);
933                         if(p->pid != pid)
934                                 error(Eprocdied);
935                         lock(&p->exl);
936                 }
937                 wq = p->waitq;
938                 p->waitq = wq->next;
939                 p->nwait--;
940                 unlock(&p->exl);
941
942                 qunlock(&p->qwaitr);
943                 poperror();
944                 n = snprint(a, n, "%d %lud %lud %lud %q",
945                         wq->w.pid,
946                         wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
947                         wq->w.msg);
948                 free(wq);
949                 return n;
950
951         case Qns:
952                 eqlock(&p->debug);
953                 if(waserror()){
954                         qunlock(&p->debug);
955                         nexterror();
956                 }
957                 if(p->pgrp == nil || p->pid != PID(c->qid))
958                         error(Eprocdied);
959                 mw = c->aux;
960                 if(mw->cddone){
961                         qunlock(&p->debug);
962                         poperror();
963                         return 0;
964                 }
965                 mntscan(mw, p);
966                 if(mw->mh == 0){
967                         mw->cddone = 1;
968                         i = snprint(a, n, "cd %s\n", p->dot->path->s);
969                         qunlock(&p->debug);
970                         poperror();
971                         return i;
972                 }
973                 int2flag(mw->cm->mflag, flag);
974                 if(strcmp(mw->cm->to->path->s, "#M") == 0){
975                         srv = srvname(mw->cm->to->mchan);
976                         i = snprint(a, n, "mount %s %s %s %s\n", flag,
977                                 srv==nil? mw->cm->to->mchan->path->s : srv,
978                                 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
979                         free(srv);
980                 }else
981                         i = snprint(a, n, "bind %s %s %s\n", flag,
982                                 mw->cm->to->path->s, mw->mh->from->path->s);
983                 qunlock(&p->debug);
984                 poperror();
985                 return i;
986
987         case Qnoteid:
988                 return readnum(offset, va, n, p->noteid, NUMSIZE);
989         case Qppid:
990                 return readnum(offset, va, n, p->parentpid, NUMSIZE);
991         case Qfd:
992                 return procfds(p, va, n, offset);
993         }
994         error(Egreg);
995         return 0;               /* not reached */
996 }
997
998 void
999 mntscan(Mntwalk *mw, Proc *p)
1000 {
1001         Pgrp *pg;
1002         Mount *t;
1003         Mhead *f;
1004         int nxt, i;
1005         ulong last, bestmid;
1006
1007         pg = p->pgrp;
1008         rlock(&pg->ns);
1009
1010         nxt = 0;
1011         bestmid = ~0;
1012
1013         last = 0;
1014         if(mw->mh)
1015                 last = mw->cm->mountid;
1016
1017         for(i = 0; i < MNTHASH; i++) {
1018                 for(f = pg->mnthash[i]; f; f = f->hash) {
1019                         for(t = f->mount; t; t = t->next) {
1020                                 if(mw->mh == 0 ||
1021                                   (t->mountid > last && t->mountid < bestmid)) {
1022                                         mw->cm = t;
1023                                         mw->mh = f;
1024                                         bestmid = mw->cm->mountid;
1025                                         nxt = 1;
1026                                 }
1027                         }
1028                 }
1029         }
1030         if(nxt == 0)
1031                 mw->mh = 0;
1032
1033         runlock(&pg->ns);
1034 }
1035
1036 static long
1037 procwrite(Chan *c, void *va, long n, vlong off)
1038 {
1039         int id, m;
1040         Proc *p, *t, *et;
1041         char *a, *arg, buf[ERRMAX];
1042         ulong offset = off;
1043
1044         a = va;
1045         if(c->qid.type & QTDIR)
1046                 error(Eisdir);
1047
1048         p = proctab(SLOT(c->qid));
1049
1050         /* Use the remembered noteid in the channel rather
1051          * than the process pgrpid
1052          */
1053         if(QID(c->qid) == Qnotepg) {
1054                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1055                 return n;
1056         }
1057
1058         eqlock(&p->debug);
1059         if(waserror()){
1060                 qunlock(&p->debug);
1061                 nexterror();
1062         }
1063         if(p->pid != PID(c->qid))
1064                 error(Eprocdied);
1065
1066         switch(QID(c->qid)){
1067         case Qargs:
1068                 if(n == 0)
1069                         error(Eshort);
1070                 if(n >= ERRMAX)
1071                         error(Etoobig);
1072                 arg = malloc(n+1);
1073                 if(arg == nil)
1074                         error(Enomem);
1075                 memmove(arg, va, n);
1076                 m = n;
1077                 if(arg[m-1] != 0)
1078                         arg[m++] = 0;
1079                 free(p->args);
1080                 p->nargs = m;
1081                 p->args = arg;
1082                 p->setargs = 1;
1083                 break;
1084
1085         case Qmem:
1086                 if(p->state != Stopped)
1087                         error(Ebadctl);
1088
1089                 n = procctlmemio(p, offset, n, va, 0);
1090                 break;
1091
1092         case Qregs:
1093                 if(offset >= sizeof(Ureg))
1094                         n = 0;
1095                 else if(offset+n > sizeof(Ureg))
1096                         n = sizeof(Ureg) - offset;
1097                 if(p->dbgreg == 0)
1098                         error(Enoreg);
1099                 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1100                 break;
1101
1102         case Qfpregs:
1103                 if(offset >= sizeof(FPsave))
1104                         n = 0;
1105                 else if(offset+n > sizeof(FPsave))
1106                         n = sizeof(FPsave) - offset;
1107                 memmove((uchar*)&p->fpsave+offset, va, n);
1108                 break;
1109
1110         case Qctl:
1111                 procctlreq(p, va, n);
1112                 break;
1113
1114         case Qnote:
1115                 if(p->kp)
1116                         error(Eperm);
1117                 if(n >= ERRMAX-1)
1118                         error(Etoobig);
1119                 memmove(buf, va, n);
1120                 buf[n] = 0;
1121                 if(!postnote(p, 0, buf, NUser))
1122                         error("note not posted");
1123                 break;
1124         case Qnoteid:
1125                 id = atoi(a);
1126                 if(id == p->pid) {
1127                         p->noteid = id;
1128                         break;
1129                 }
1130                 t = proctab(0);
1131                 for(et = t+conf.nproc; t < et; t++) {
1132                         if(t->state == Dead)
1133                                 continue;
1134                         if(id == t->noteid) {
1135                                 if(strcmp(p->user, t->user) != 0)
1136                                         error(Eperm);
1137                                 p->noteid = id;
1138                                 break;
1139                         }
1140                 }
1141                 if(p->noteid != id)
1142                         error(Ebadarg);
1143                 break;
1144         default:
1145                 pprint("unknown qid in procwrite\n");
1146                 error(Egreg);
1147         }
1148         poperror();
1149         qunlock(&p->debug);
1150         return n;
1151 }
1152
1153 Dev procdevtab = {
1154         'p',
1155         "proc",
1156
1157         devreset,
1158         procinit,
1159         devshutdown,
1160         procattach,
1161         procwalk,
1162         procstat,
1163         procopen,
1164         devcreate,
1165         procclose,
1166         procread,
1167         devbread,
1168         procwrite,
1169         devbwrite,
1170         devremove,
1171         procwstat,
1172 };
1173
1174 Chan*
1175 proctext(Chan *c, Proc *p)
1176 {
1177         Chan *tc;
1178         Image *i;
1179         Segment *s;
1180
1181         s = p->seg[TSEG];
1182         if(s == 0)
1183                 error(Enonexist);
1184         if(p->state==Dead)
1185                 error(Eprocdied);
1186
1187         lock(s);
1188         i = s->image;
1189         if(i == 0) {
1190                 unlock(s);
1191                 error(Eprocdied);
1192         }
1193         unlock(s);
1194
1195         lock(i);
1196         if(waserror()) {
1197                 unlock(i);
1198                 nexterror();
1199         }
1200
1201         tc = i->c;
1202         if(tc == 0)
1203                 error(Eprocdied);
1204
1205         if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1206                 cclose(tc);
1207                 error(Eprocdied);
1208         }
1209
1210         if(p->pid != PID(c->qid)) {
1211                 cclose(tc);
1212                 error(Eprocdied);
1213         }
1214
1215         unlock(i);
1216         poperror();
1217
1218         return tc;
1219 }
1220
1221 void
1222 procstopwait(Proc *p, int ctl)
1223 {
1224         int pid;
1225
1226         if(p->pdbg)
1227                 error(Einuse);
1228         if(procstopped(p) || p->state == Broken)
1229                 return;
1230
1231         if(ctl != 0)
1232                 p->procctl = ctl;
1233         p->pdbg = up;
1234         pid = p->pid;
1235         qunlock(&p->debug);
1236         up->psstate = "Stopwait";
1237         if(waserror()) {
1238                 p->pdbg = 0;
1239                 qlock(&p->debug);
1240                 nexterror();
1241         }
1242         sleep(&up->sleep, procstopped, p);
1243         poperror();
1244         qlock(&p->debug);
1245         if(p->pid != pid)
1246                 error(Eprocdied);
1247 }
1248
1249 static void
1250 procctlcloseone(Proc *p, Fgrp *f, int fd)
1251 {
1252         Chan *c;
1253
1254         c = f->fd[fd];
1255         if(c == nil)
1256                 return;
1257         f->fd[fd] = nil;
1258         unlock(f);
1259         qunlock(&p->debug);
1260         cclose(c);
1261         qlock(&p->debug);
1262         lock(f);
1263 }
1264
1265 void
1266 procctlclosefiles(Proc *p, int all, int fd)
1267 {
1268         int i;
1269         Fgrp *f;
1270
1271         f = p->fgrp;
1272         if(f == nil)
1273                 error(Eprocdied);
1274
1275         lock(f);
1276         f->ref++;
1277         if(all)
1278                 for(i = 0; i < f->maxfd; i++)
1279                         procctlcloseone(p, f, i);
1280         else
1281                 procctlcloseone(p, f, fd);
1282         unlock(f);
1283         closefgrp(f);
1284 }
1285
1286 static char *
1287 parsetime(vlong *rt, char *s)
1288 {
1289         uvlong ticks;
1290         ulong l;
1291         char *e, *p;
1292         static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1293
1294         if (s == nil)
1295                 return("missing value");
1296         ticks=strtoul(s, &e, 10);
1297         if (*e == '.'){
1298                 p = e+1;
1299                 l = strtoul(p, &e, 10);
1300                 if(e-p > nelem(p10))
1301                         return "too many digits after decimal point";
1302                 if(e-p == 0)
1303                         return "ill-formed number";
1304                 l *= p10[e-p-1];
1305         }else
1306                 l = 0;
1307         if (*e == '\0' || strcmp(e, "s") == 0){
1308                 ticks = 1000000000 * ticks + l;
1309         }else if (strcmp(e, "ms") == 0){
1310                 ticks = 1000000 * ticks + l/1000;
1311         }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1312                 ticks = 1000 * ticks + l/1000000;
1313         }else if (strcmp(e, "ns") != 0)
1314                 return "unrecognized unit";
1315         *rt = ticks;
1316         return nil;
1317 }
1318
1319 void
1320 procctlreq(Proc *p, char *va, int n)
1321 {
1322         Segment *s;
1323         int npc, pri;
1324         Cmdbuf *cb;
1325         Cmdtab *ct;
1326         vlong time;
1327         char *e;
1328         void (*pt)(Proc*, int, vlong);
1329
1330         if(p->kp)       /* no ctl requests to kprocs */
1331                 error(Eperm);
1332
1333         cb = parsecmd(va, n);
1334         if(waserror()){
1335                 free(cb);
1336                 nexterror();
1337         }
1338
1339         ct = lookupcmd(cb, proccmd, nelem(proccmd));
1340
1341         switch(ct->index){
1342         case CMclose:
1343                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1344                 break;
1345         case CMclosefiles:
1346                 procctlclosefiles(p, 1, 0);
1347                 break;
1348         case CMhang:
1349                 p->hang = 1;
1350                 break;
1351         case CMkill:
1352                 switch(p->state) {
1353                 case Broken:
1354                         unbreak(p);
1355                         break;
1356                 case Stopped:
1357                         p->procctl = Proc_exitme;
1358                         postnote(p, 0, "sys: killed", NExit);
1359                         ready(p);
1360                         break;
1361                 default:
1362                         p->procctl = Proc_exitme;
1363                         postnote(p, 0, "sys: killed", NExit);
1364                 }
1365                 break;
1366         case CMnohang:
1367                 p->hang = 0;
1368                 break;
1369         case CMnoswap:
1370                 p->noswap = 1;
1371                 break;
1372         case CMpri:
1373                 pri = atoi(cb->f[1]);
1374                 if(pri > PriNormal && !iseve())
1375                         error(Eperm);
1376                 procpriority(p, pri, 0);
1377                 break;
1378         case CMfixedpri:
1379                 pri = atoi(cb->f[1]);
1380                 if(pri > PriNormal && !iseve())
1381                         error(Eperm);
1382                 procpriority(p, pri, 1);
1383                 break;
1384         case CMprivate:
1385                 p->privatemem = 1;
1386                 break;
1387         case CMprofile:
1388                 s = p->seg[TSEG];
1389                 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1390                         error(Ebadctl);
1391                 if(s->profile != 0)
1392                         free(s->profile);
1393                 npc = (s->top-s->base)>>LRESPROF;
1394                 s->profile = malloc(npc*sizeof(*s->profile));
1395                 if(s->profile == 0)
1396                         error(Enomem);
1397                 break;
1398         case CMstart:
1399                 if(p->state != Stopped)
1400                         error(Ebadctl);
1401                 ready(p);
1402                 break;
1403         case CMstartstop:
1404                 if(p->state != Stopped)
1405                         error(Ebadctl);
1406                 p->procctl = Proc_traceme;
1407                 ready(p);
1408                 procstopwait(p, Proc_traceme);
1409                 break;
1410         case CMstartsyscall:
1411                 if(p->state != Stopped)
1412                         error(Ebadctl);
1413                 p->procctl = Proc_tracesyscall;
1414                 ready(p);
1415                 procstopwait(p, Proc_tracesyscall);
1416                 break;
1417         case CMstop:
1418                 procstopwait(p, Proc_stopme);
1419                 break;
1420         case CMwaitstop:
1421                 procstopwait(p, 0);
1422                 break;
1423         case CMwired:
1424                 procwired(p, atoi(cb->f[1]));
1425                 break;
1426         case CMtrace:
1427                 switch(cb->nf){
1428                 case 1:
1429                         p->trace ^= 1;
1430                         break;
1431                 case 2:
1432                         p->trace = (atoi(cb->f[1]) != 0);
1433                         break;
1434                 default:
1435                         error("args");
1436                 }
1437                 break;
1438         case CMinterrupt:
1439                 postnote(p, 0, nil, NUser);
1440                 break;
1441         case CMnointerrupt:
1442                 if(p->nnote == 0)
1443                         p->notepending = 0;
1444                 else
1445                         error("notes pending");
1446                 break;
1447         /* real time */
1448         case CMperiod:
1449                 if(p->edf == nil)
1450                         edfinit(p);
1451                 if(e=parsetime(&time, cb->f[1]))        /* time in ns */
1452                         error(e);
1453                 edfstop(p);
1454                 p->edf->T = time/1000;  /* Edf times are in µs */
1455                 break;
1456         case CMdeadline:
1457                 if(p->edf == nil)
1458                         edfinit(p);
1459                 if(e=parsetime(&time, cb->f[1]))
1460                         error(e);
1461                 edfstop(p);
1462                 p->edf->D = time/1000;
1463                 break;
1464         case CMcost:
1465                 if(p->edf == nil)
1466                         edfinit(p);
1467                 if(e=parsetime(&time, cb->f[1]))
1468                         error(e);
1469                 edfstop(p);
1470                 p->edf->C = time/1000;
1471                 break;
1472         case CMsporadic:
1473                 if(p->edf == nil)
1474                         edfinit(p);
1475                 p->edf->flags |= Sporadic;
1476                 break;
1477         case CMdeadlinenotes:
1478                 if(p->edf == nil)
1479                         edfinit(p);
1480                 p->edf->flags |= Sendnotes;
1481                 break;
1482         case CMadmit:
1483                 if(p->edf == 0)
1484                         error("edf params");
1485                 if(e = edfadmit(p))
1486                         error(e);
1487                 break;
1488         case CMextra:
1489                 if(p->edf == nil)
1490                         edfinit(p);
1491                 p->edf->flags |= Extratime;
1492                 break;
1493         case CMexpel:
1494                 if(p->edf)
1495                         edfstop(p);
1496                 break;
1497         case CMevent:
1498                 pt = proctrace;
1499                 if(up->trace && pt)
1500                         pt(up, SUser, 0);
1501                 break;
1502         }
1503
1504         poperror();
1505         free(cb);
1506 }
1507
1508 int
1509 procstopped(void *a)
1510 {
1511         Proc *p = a;
1512         return p->state == Stopped;
1513 }
1514
1515 int
1516 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1517 {
1518         KMap *k;
1519         Pte *pte;
1520         Page *pg;
1521         Segment *s;
1522         ulong soff, l;
1523         char *a = va, *b;
1524
1525         for(;;) {
1526                 s = seg(p, offset, 1);
1527                 if(s == 0)
1528                         error(Ebadarg);
1529
1530                 if(offset+n >= s->top)
1531                         n = s->top-offset;
1532
1533                 if(!read && (s->type&SG_TYPE) == SG_TEXT)
1534                         s = txt2data(p, s);
1535
1536                 s->steal++;
1537                 soff = offset-s->base;
1538                 if(waserror()) {
1539                         s->steal--;
1540                         nexterror();
1541                 }
1542                 if(fixfault(s, offset, read, 0) == 0)
1543                         break;
1544                 poperror();
1545                 s->steal--;
1546         }
1547         poperror();
1548         pte = s->map[soff/PTEMAPMEM];
1549         if(pte == 0)
1550                 panic("procctlmemio");
1551         pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1552         if(pagedout(pg))
1553                 panic("procctlmemio1");
1554
1555         l = BY2PG - (offset&(BY2PG-1));
1556         if(n > l)
1557                 n = l;
1558
1559         k = kmap(pg);
1560         if(waserror()) {
1561                 s->steal--;
1562                 kunmap(k);
1563                 nexterror();
1564         }
1565         b = (char*)VA(k);
1566         b += offset&(BY2PG-1);
1567         if(read == 1)
1568                 memmove(a, b, n);       /* This can fault */
1569         else
1570                 memmove(b, a, n);
1571         kunmap(k);
1572         poperror();
1573
1574         /* Ensure the process sees text page changes */
1575         if(s->flushme)
1576                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1577
1578         s->steal--;
1579
1580         if(read == 0)
1581                 p->newtlb = 1;
1582
1583         return n;
1584 }
1585
1586 Segment*
1587 txt2data(Proc *p, Segment *s)
1588 {
1589         int i;
1590         Segment *ps;
1591
1592         ps = newseg(SG_DATA, s->base, s->size);
1593         ps->image = s->image;
1594         incref(ps->image);
1595         ps->fstart = s->fstart;
1596         ps->flen = s->flen;
1597         ps->flushme = 1;
1598
1599         qlock(&p->seglock);
1600         for(i = 0; i < NSEG; i++)
1601                 if(p->seg[i] == s)
1602                         break;
1603         if(i == NSEG)
1604                 panic("segment gone");
1605
1606         qunlock(&s->lk);
1607         putseg(s);
1608         qlock(&ps->lk);
1609         p->seg[i] = ps;
1610         qunlock(&p->seglock);
1611
1612         return ps;
1613 }
1614
1615 Segment*
1616 data2txt(Segment *s)
1617 {
1618         Segment *ps;
1619
1620         ps = newseg(SG_TEXT, s->base, s->size);
1621         ps->image = s->image;
1622         incref(ps->image);
1623         ps->fstart = s->fstart;
1624         ps->flen = s->flen;
1625         ps->flushme = 1;
1626
1627         return ps;
1628 }