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