Remove the last vestiges of the old syscall tracer
[akaros.git] / kern / drivers / dev / proc.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 //#define DEBUG
11 /* proc on plan 9 has lots of capabilities, some of which we might
12  * want for akaros:
13  * debug control
14  * event tracing
15  * process control (no need for signal system call, etc.)
16  * textual status
17  * rather than excise code that won't work, I'm bracketing it with
18  * #if 0 until we know we don't want it
19  */
20 #include <vfs.h>
21 #include <kfs.h>
22 #include <slab.h>
23 #include <kmalloc.h>
24 #include <kref.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <assert.h>
28 #include <error.h>
29 #include <cpio.h>
30 #include <pmap.h>
31 #include <smp.h>
32 #include <arch/vmm/vmm.h>
33 #include <ros/vmm.h>
34
35 struct dev procdevtab;
36
37 static char *devname(void)
38 {
39         return procdevtab.name;
40 }
41
42 enum {
43         Qdir,
44         Qtrace,
45         Qtracepids,
46         Qns,
47         Qargs,
48         Qctl,
49         Qfd,
50         Qfpregs,
51         Qkregs,
52         Qmem,
53         Qnote,
54         Qnoteid,
55         Qnotepg,
56         Qproc,
57         Qregs,
58         Qsegment,
59         Qstatus,
60         Qstrace,
61         Qvmstatus,
62         Qtext,
63         Qwait,
64         Qprofile,
65         Qsyscall,
66         Qcore,
67 };
68
69 enum {
70         CMclose,
71         CMclosefiles,
72         CMfixedpri,
73         CMhang,
74         CMkill,
75         CMnohang,
76         CMnoswap,
77         CMpri,
78         CMprivate,
79         CMprofile,
80         CMstart,
81         CMstartstop,
82         CMstartsyscall,
83         CMstop,
84         CMwaitstop,
85         CMwired,
86         CMcore,
87         CMvminit,
88         CMvmstart,
89         CMvmkill,
90         CMstraceme,
91         CMstraceall,
92         CMstraceoff,
93 };
94
95 enum {
96         Nevents = 0x4000,
97         Emask = Nevents - 1,
98         Ntracedpids = 1024,
99         STATSIZE = 8 + 1 + 10 + 1 + 6 + 2,
100 };
101
102 /*
103  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
104  * particularly on shared servers.
105  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
106  */
107 struct dirtab procdir[] = {
108         {"args", {Qargs}, 0, 0660},
109         {"ctl", {Qctl}, 0, 0660},
110         {"fd", {Qfd}, 0, 0444},
111         {"fpregs", {Qfpregs}, 0, 0000},
112         //  {"kregs",   {Qkregs},   sizeof(Ureg),       0600},
113         {"mem", {Qmem}, 0, 0000},
114         {"note", {Qnote}, 0, 0000},
115         {"noteid", {Qnoteid}, 0, 0664},
116         {"notepg", {Qnotepg}, 0, 0000},
117         {"ns", {Qns}, 0, 0444},
118         {"proc", {Qproc}, 0, 0400},
119         //  {"regs",        {Qregs},    sizeof(Ureg),       0000},
120         {"segment", {Qsegment}, 0, 0444},
121         {"status", {Qstatus}, STATSIZE, 0444},
122         {"strace", {Qstrace}, 0, 0666},
123         {"vmstatus", {Qvmstatus}, 0, 0444},
124         {"text", {Qtext}, 0, 0000},
125         {"wait", {Qwait}, 0, 0400},
126         {"profile", {Qprofile}, 0, 0400},
127         {"syscall", {Qsyscall}, 0, 0400},
128         {"core", {Qcore}, 0, 0444},
129 };
130
131 static
132 struct cmdtab proccmd[] = {
133         {CMclose, "close", 2},
134         {CMclosefiles, "closefiles", 1},
135         {CMfixedpri, "fixedpri", 2},
136         {CMhang, "hang", 1},
137         {CMnohang, "nohang", 1},
138         {CMnoswap, "noswap", 1},
139         {CMkill, "kill", 1},
140         {CMpri, "pri", 2},
141         {CMprivate, "private", 1},
142         {CMprofile, "profile", 1},
143         {CMstart, "start", 1},
144         {CMstartstop, "startstop", 1},
145         {CMstartsyscall, "startsyscall", 1},
146         {CMstop, "stop", 1},
147         {CMwaitstop, "waitstop", 1},
148         {CMwired, "wired", 2},
149         {CMcore, "core", 2},
150         {CMcore, "core", 2},
151         {CMcore, "core", 2},
152         {CMvminit, "vminit", 0},
153         {CMvmstart, "vmstart", 0},
154         {CMvmkill, "vmkill", 0},
155         {CMstraceme, "straceme", 0},
156         {CMstraceall, "straceall", 0},
157         {CMstraceoff, "straceoff", 0},
158 };
159
160 /*
161  * struct qids are, in path:
162  *       5 bits of file type (qids above) (old comment said 4 here)
163  *      23 bits of process slot number + 1 (pid + 1 is stored)
164  *           in vers,
165  *      32 bits of pid, for consistency checking
166  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
167  */
168 #define QSHIFT  5       /* location in qid of proc slot # */
169 #define SLOTBITS 23     /* number of bits in the slot */
170 #define QIDMASK ((1<<QSHIFT)-1)
171 #define SLOTMASK        (((1<<SLOTBITS)-1) << QSHIFT)
172
173 #define QID(q)          ((((uint32_t)(q).path)&QIDMASK)>>0)
174 #define SLOT(q)         (((((uint32_t)(q).path)&SLOTMASK)>>QSHIFT)-1)
175 #define PID(q)          ((q).vers)
176 #define NOTEID(q)       ((q).vers)
177
178 static void procctlreq(struct proc *, char *, int);
179 static int procctlmemio(struct proc *, uintptr_t, int, void *, int);
180 //static struct chan*   proctext(struct chan*, struct proc*);
181 //static Segment* txt2data(struct proc*, Segment*);
182 //static int    procstopped(void*);
183 static void mntscan(struct mntwalk *, struct proc *);
184
185 //static Traceevent *tevents;
186 static char *tpids, *tpidsc, *tpidse;
187 static spinlock_t tlock;
188 static int topens;
189 static int tproduced, tconsumed;
190 //static void notrace(struct proc*, int, int64_t);
191
192 //void (*proctrace)(struct proc*, int, int64_t) = notrace;
193
194 #if 0
195 static void profclock(Ureg * ur, Timer *)
196 {
197         Tos *tos;
198
199         if (up == NULL || current->state != Running)
200                 return;
201
202         /* user profiling clock */
203         if (userureg(ur)) {
204                 tos = (Tos *) (USTKTOP - sizeof(Tos));
205                 tos->clock += TK2MS(1);
206                 segclock(userpc(ur));
207         }
208 }
209 #endif
210 static int
211 procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
212                 struct dir *dp)
213 {
214         struct qid qid;
215         struct proc *p;
216         char *ename;
217
218         int pid;
219         uint32_t path, perm, len;
220         if (s == DEVDOTDOT) {
221                 mkqid(&qid, Qdir, 0, QTDIR);
222                 devdir(c, qid, devname(), 0, eve, 0555, dp);
223                 return 1;
224         }
225
226         if (c->qid.path == Qdir) {
227                 if (s == 0) {
228                         strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
229                         mkqid(&qid, Qtrace, -1, QTFILE);
230                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
231                         return 1;
232                 }
233                 if (s == 1) {
234                         strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
235                         mkqid(&qid, Qtracepids, -1, QTFILE);
236                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
237                         return 1;
238                 }
239                 s -= 2;
240                 if (name != NULL) {
241                         /* ignore s and use name to find pid */
242                         pid = strtol(name, &ename, 10);
243                         if (pid <= 0 || ename[0] != '\0')
244                                 return -1;
245                         p = pid2proc(pid);
246                         if (!p)
247                                 return -1;
248                         /* Need to update s, so that it's the correct 'index' for our proc
249                          * (aka, the pid).  We use s later when making the qid. */
250                         s = pid;
251                 } else {
252                         /* This is a shitty iterator, and the list isn't guaranteed to give
253                          * you the same ordering twice in a row. (procs come and go). */
254                         p = pid_nth(s);
255                         if (!p)
256                                 return -1;
257                         pid = p->pid;
258                 }
259
260                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%u", pid);
261                 /*
262                  * String comparison is done in devwalk so
263                  * name must match its formatted pid.
264                  */
265                 if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
266                         printk("pid-name mismatch, name: %s, pid %d\n", name, pid);
267                         kref_put(&p->p_kref);
268                         return -1;
269                 }
270                 mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
271                 devdir(c, qid, get_cur_genbuf(), 0, p->user, DMDIR | 0555, dp);
272                 kref_put(&p->p_kref);
273                 return 1;
274         }
275         if (c->qid.path == Qtrace) {
276                 strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
277                 mkqid(&qid, Qtrace, -1, QTFILE);
278                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
279                 return 1;
280         }
281         if (c->qid.path == Qtracepids) {
282                 strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
283                 mkqid(&qid, Qtracepids, -1, QTFILE);
284                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
285                 return 1;
286         }
287         if (s >= ARRAY_SIZE(procdir))
288                 return -1;
289         if (tab)
290                 panic("procgen");
291
292         tab = &procdir[s];
293         /* path is everything other than the QID part.  Not sure from the orig code
294          * if they wanted just the pid part (SLOTMASK) or everything above QID */
295         path = c->qid.path & ~QIDMASK;  /* slot component */
296         if ((p = pid2proc(SLOT(c->qid))) == NULL)
297                 return -1;
298         perm = 0444 | tab->perm;
299 #if 0
300         if (perm == 0)
301                 perm = p->procmode;
302         else    /* just copy read bits */
303                 perm |= p->procmode & 0444;
304 #endif
305
306         len = tab->length;
307 #if 0
308         switch (QID(c->qid)) {
309                 case Qwait:
310                         len = p->nwait; /* incorrect size, but >0 means there's something to read */
311                         break;
312                 case Qprofile:
313                         q = p->seg[TSEG];
314                         if (q && q->profile) {
315                                 len = (q->top - q->base) >> LRESPROF;
316                                 len *= sizeof(*q->profile);
317                         }
318                         break;
319         }
320 #endif
321
322         mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
323         devdir(c, qid, tab->name, len, p->user, perm, dp);
324         kref_put(&p->p_kref);
325         return 1;
326 }
327
328 #if 0
329 static void notrace(struct proc *, Tevent, int64_t)
330 {
331 }
332
333 static spinlock_t tlck = SPINLOCK_INITIALIZER_IRQSAVE;
334
335 static void _proctrace(struct proc *p, Tevent etype, int64_t ts)
336 {
337         Traceevent *te;
338         int tp;
339
340         ilock(&tlck);
341         if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) {
342                 iunlock(&tlck);
343                 return;
344         }
345         tp = tproduced++;
346         iunlock(&tlck);
347
348         te = &tevents[tp & Emask];
349         te->pid = p->pid;
350         te->etype = etype;
351         if (ts == 0)
352                 te->time = todget(NULL);
353         else
354                 te->time = ts;
355         te->core = m->machno;
356 }
357
358 void proctracepid(struct proc *p)
359 {
360         if (p->trace == 1 && proctrace != notrace) {
361                 p->trace = 2;
362                 ilock(&tlck);
363                 tpidsc = seprint(tpidsc, tpidse, "%d %s\n", p->pid, p->text);
364                 iunlock(&tlck);
365         }
366 }
367
368 #endif
369 static void procinit(void)
370 {
371 #if 0
372         if (conf.nproc >= (SLOTMASK >> QSHIFT) - 1)
373                 printd("warning: too many procs for devproc\n");
374         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
375 #endif
376 }
377
378 static struct chan *procattach(char *spec)
379 {
380         return devattach(devname(), spec);
381 }
382
383 static struct walkqid *procwalk(struct chan *c, struct chan *nc, char **name,
384                                                                 int nname)
385 {
386         return devwalk(c, nc, name, nname, 0, 0, procgen);
387 }
388
389 static int procstat(struct chan *c, uint8_t * db, int n)
390 {
391         return devstat(c, db, n, 0, 0, procgen);
392 }
393
394 /*
395  *  none can't read or write state on other
396  *  processes.  This is to contain access of
397  *  servers running as none should they be
398  *  subverted by, for example, a stack attack.
399  */
400 static void nonone(struct proc *p)
401 {
402         return;
403 #if 0
404         if (p == up)
405                 return;
406         if (strcmp(current->user, "none") != 0)
407                 return;
408         if (iseve())
409                 return;
410         error(EPERM, ERROR_FIXME);
411 #endif
412 }
413
414 static struct chan *procopen(struct chan *c, int omode)
415 {
416         ERRSTACK(2);
417         struct proc *p;
418         struct pgrp *pg;
419         struct chan *tc;
420         int pid;
421
422         if (c->qid.type & QTDIR)
423                 return devopen(c, omode, 0, 0, procgen);
424
425         if (QID(c->qid) == Qtrace) {
426                 error(ENOSYS, ERROR_FIXME);
427 #if 0
428                 if (omode != OREAD)
429                         error(EPERM, ERROR_FIXME);
430                 lock(&tlock);
431                 if (waserror()) {
432                         unlock(&tlock);
433                         nexterror();
434                 }
435                 if (topens > 0)
436                         error(EFAIL, "already open");
437                 topens++;
438                 if (tevents == NULL) {
439                         tevents = (Traceevent *) kzmalloc(sizeof(Traceevent) * Nevents,
440                                                                                           MEM_WAIT);
441                         if (tevents == NULL)
442                                 error(ENOMEM, ERROR_FIXME);
443                         tpids = kzmalloc(Ntracedpids * 20, MEM_WAIT);
444                         if (tpids == NULL) {
445                                 kfree(tpids);
446                                 tpids = NULL;
447                                 error(ENOMEM, ERROR_FIXME);
448                         }
449                         tpidsc = tpids;
450                         tpidse = tpids + Ntracedpids * 20;
451                         *tpidsc = 0;
452                         tproduced = tconsumed = 0;
453                 }
454                 proctrace = _proctrace;
455                 poperror();
456                 unlock(&tlock);
457
458                 c->mode = openmode(omode);
459                 c->flag |= COPEN;
460                 c->offset = 0;
461                 return c;
462 #endif
463         }
464         if (QID(c->qid) == Qtracepids) {
465                 error(ENOSYS, ERROR_FIXME);
466 #if 0
467                 if (omode != OREAD)
468                         error(EPERM, ERROR_FIXME);
469                 c->mode = openmode(omode);
470                 c->flag |= COPEN;
471                 c->offset = 0;
472                 return c;
473 #endif
474         }
475         if ((p = pid2proc(SLOT(c->qid))) == NULL)
476                 error(ESRCH, ERROR_FIXME);
477         //qlock(&p->debug);
478         if (waserror()) {
479                 //qunlock(&p->debug);
480                 kref_put(&p->p_kref);
481                 nexterror();
482         }
483         pid = PID(c->qid);
484         if (p->pid != pid)
485                 error(ESRCH, ERROR_FIXME);
486
487         omode = openmode(omode);
488
489         switch (QID(c->qid)) {
490                 case Qtext:
491                         error(ENOSYS, ERROR_FIXME);
492 /*
493                         if (omode != OREAD)
494                                 error(EPERM, ERROR_FIXME);
495                         tc = proctext(c, p);
496                         tc->offset = 0;
497                         poperror();
498                         qunlock(&p->debug);
499                         kref_put(&p->p_kref);
500                         cclose(c);
501                         return tc;
502 */
503                 case Qproc:
504                 case Qsegment:
505                 case Qprofile:
506                 case Qfd:
507                         if (omode != O_READ)
508                                 error(EPERM, ERROR_FIXME);
509                         break;
510
511                 case Qnote:
512 //          if (p->privatemem)
513                         error(EPERM, ERROR_FIXME);
514                         break;
515
516                 case Qmem:
517 //          if (p->privatemem)
518                         error(EPERM, ERROR_FIXME);
519                         //nonone(p);
520                         break;
521
522                 case Qargs:
523                 case Qnoteid:
524                 case Qwait:
525                 case Qregs:
526                 case Qfpregs:
527                 case Qkregs:
528                 case Qsyscall:
529                 case Qcore:
530                         nonone(p);
531                         break;
532
533                 case Qns:
534                         if (omode != O_READ)
535                                 error(EPERM, ERROR_FIXME);
536                         c->aux = kzmalloc(sizeof(struct mntwalk), MEM_WAIT);
537                         break;
538                 case Qstatus:
539                 case Qvmstatus:
540                 case Qctl:
541                         break;
542
543                 case Qstrace:
544                         if (!p->strace)
545                                 error(ENOENT, "Process does not have tracing enabled");
546                         /* the ref we are upping is the one we put in __proc_free, which is
547                          * the one we got from CMstrace{on,me}.  We have a ref on p, so we
548                          * know we won't free until we decref the proc. */
549                         kref_get(&p->strace->users, 1);
550                         c->aux = p->strace;
551                         break;
552                 case Qnotepg:
553                         error(ENOSYS, ERROR_FIXME);
554 #if 0
555                         nonone(p);
556                         pg = p->pgrp;
557                         if (pg == NULL)
558                                 error(ESRCH, ERROR_FIXME);
559                         if (omode != OWRITE || pg->pgrpid == 1)
560                                 error(EPERM, ERROR_FIXME);
561                         c->pgrpid.path = pg->pgrpid + 1;
562                         c->pgrpid.vers = p->noteid;
563 #endif
564                         break;
565
566                 default:
567                         printk("procopen %#llux\n", c->qid.path);
568                         error(EINVAL, ERROR_FIXME);
569         }
570
571         /* Affix pid to qid */
572 //  if (p->state != Dead)
573         c->qid.vers = p->pid;
574         /* make sure the process slot didn't get reallocated while we were playing */
575         //coherence();
576         /* TODO: think about what we really want here.  In akaros, we wouldn't have
577          * our pid changed like that. */
578         if (p->pid != pid)
579                 error(ESRCH, ERROR_FIXME);
580
581         tc = devopen(c, omode, 0, 0, procgen);
582         poperror();
583         //qunlock(&p->debug);
584         kref_put(&p->p_kref);
585         return tc;
586 }
587
588 static int procwstat(struct chan *c, uint8_t * db, int n)
589 {
590         ERRSTACK(2);
591         error(ENOSYS, ERROR_FIXME);
592 #if 0
593         struct proc *p;
594         struct dir *d;
595
596         if (c->qid.type & QTDIR)
597                 error(EPERM, ERROR_FIXME);
598
599         if (QID(c->qid) == Qtrace)
600                 return devwstat(c, db, n);
601
602         if ((p = pid2proc(SLOT(c->qid))) == NULL)
603                 error(ESRCH, ERROR_FIXME);
604         nonone(p);
605         d = NULL;
606         qlock(&p->debug);
607         if (waserror()) {
608                 qunlock(&p->debug);
609                 kref_put(&p->p_kref);
610                 kfree(d);
611                 nexterror();
612         }
613
614         if (p->pid != PID(c->qid))
615                 error(ESRCH, ERROR_FIXME);
616
617         if (strcmp(current->user, p->user) != 0 && strcmp(current->user, eve) != 0)
618                 error(EPERM, ERROR_FIXME);
619
620         d = kzmalloc(sizeof(struct dir) + n, MEM_WAIT);
621         n = convM2D(db, n, &d[0], (char *)&d[1]);
622         if (n == 0)
623                 error(ENOENT, ERROR_FIXME);
624         if (!emptystr(d->uid) && strcmp(d->uid, p->user) != 0) {
625                 if (strcmp(current->user, eve) != 0)
626                         error(EPERM, ERROR_FIXME);
627                 else
628                         kstrdup(&p->user, d->uid);
629         }
630         if (d->mode != ~0UL)
631                 p->procmode = d->mode & 0777;
632
633         poperror();
634         qunlock(&p->debug);
635         kref_put(&p->p_kref);
636         kfree(d);
637
638         return n;
639 #endif
640 }
641
642 #if 0
643 static long procoffset(long offset, char *va, int *np)
644 {
645         if (offset > 0) {
646                 offset -= *np;
647                 if (offset < 0) {
648                         memmove(va, va + *np + offset, -offset);
649                         *np = -offset;
650                 } else
651                         *np = 0;
652         }
653         return offset;
654 }
655
656 static int procqidwidth(struct chan *c)
657 {
658         char buf[32];
659
660         return sprint(buf, "%lu", c->qid.vers);
661 }
662
663 int procfdprint(struct chan *c, int fd, int w, char *s, int ns)
664 {
665         int n;
666
667         if (w == 0)
668                 w = procqidwidth(c);
669         n = snprint(s, ns,
670                                 "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd,
671                                 &"r w rw"[(c->mode & 3) << 1], c->dev->dc, c->devno,
672                                 c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset,
673                                 c->name->s);
674         return n;
675 }
676
677 static int procfds(struct proc *p, char *va, int count, long offset)
678 {
679         ERRSTACK(2);
680         struct fgrp *f;
681         struct chan *c;
682         char buf[256];
683         int n, i, w, ww;
684         char *a;
685
686         /* print to buf to avoid holding fgrp lock while writing to user space */
687         if (count > sizeof buf)
688                 count = sizeof buf;
689         a = buf;
690
691         qlock(&p->debug);
692         f = p->fgrp;
693         if (f == NULL) {
694                 qunlock(&p->debug);
695                 return 0;
696         }
697         lock(f);
698         if (waserror()) {
699                 unlock(f);
700                 qunlock(&p->debug);
701                 nexterror();
702         }
703
704         n = readstr(0, a, count, p->dot->name->s);
705         n += snprint(a + n, count - n, "\n");
706         offset = procoffset(offset, a, &n);
707         /* compute width of qid.path */
708         w = 0;
709         for (i = 0; i <= f->maxfd; i++) {
710                 c = f->fd[i];
711                 if (c == NULL)
712                         continue;
713                 ww = procqidwidth(c);
714                 if (ww > w)
715                         w = ww;
716         }
717         for (i = 0; i <= f->maxfd; i++) {
718                 c = f->fd[i];
719                 if (c == NULL)
720                         continue;
721                 n += procfdprint(c, i, w, a + n, count - n);
722                 offset = procoffset(offset, a, &n);
723         }
724         poperror();
725         unlock(f);
726         qunlock(&p->debug);
727
728         /* copy result to user space, now that locks are released */
729         memmove(va, buf, n);
730
731         return n;
732 }
733 #endif
734 static void procclose(struct chan *c)
735 {
736         if (QID(c->qid) == Qtrace) {
737                 spin_lock(&tlock);
738                 if (topens > 0)
739                         topens--;
740                 /* ??
741                    if(topens == 0)
742                    proctrace = notrace;
743                  */
744                 spin_unlock(&tlock);
745         }
746         if (QID(c->qid) == Qsyscall) {
747                 if (c->aux)
748                         qclose(c->aux);
749                 c->aux = NULL;
750         }
751         if (QID(c->qid) == Qns && c->aux != 0)
752                 kfree(c->aux);
753         if (QID(c->qid) == Qstrace && c->aux != 0) {
754                 struct strace *s = c->aux;
755
756                 kref_put(&s->users);
757                 c->aux = NULL;
758         }
759 }
760
761 void int2flag(int flag, char *s)
762 {
763         if (flag == 0) {
764                 *s = '\0';
765                 return;
766         }
767         *s++ = '-';
768         if (flag & MAFTER)
769                 *s++ = 'a';
770         if (flag & MBEFORE)
771                 *s++ = 'b';
772         if (flag & MCREATE)
773                 *s++ = 'c';
774         if (flag & MCACHE)
775                 *s++ = 'C';
776         *s = '\0';
777 }
778
779 #if 0
780 static char *argcpy(char *s, char *p)
781 {
782         char *t, *tp, *te;
783         int n;
784
785         n = p - s;
786         if (n > 128)
787                 n = 128;
788         if (n <= 0) {
789                 t = kzmalloc(1, MEM_WAIT);
790                 *t = 0;
791                 return t;
792         }
793         t = kzmalloc(n, MEM_WAIT);
794         tp = t;
795         te = t + n;
796
797         while (tp + 1 < te) {
798                 for (p--; p > s && p[-1] != 0; p--) ;
799                 tp = seprint(tp, te, "%q ", p);
800                 if (p == s)
801                         break;
802         }
803         if (*tp == ' ')
804                 *tp = 0;
805         return t;
806 }
807
808 static int procargs(struct proc *p, char *buf, int nbuf)
809 {
810         char *s;
811
812         if (p->setargs == 0) {
813                 s = argcpy(p->args, p->args + p->nargs);
814                 kfree(p->args);
815                 p->nargs = strlen(s);
816                 p->args = s;
817                 p->setargs = 1;
818         }
819         return snprint(buf, nbuf, "%s", p->args);
820 }
821
822 static int eventsavailable(void *)
823 {
824         return tproduced > tconsumed;
825 }
826 #endif
827 static long procread(struct chan *c, void *va, long n, int64_t off)
828 {
829         ERRSTACK(1);
830         struct proc *p;
831         long l, r;
832         int i, j, navail, pid, rsize;
833         char flag[10], *sps, *srv;
834         uintptr_t offset, u;
835         int tesz;
836         uint8_t *rptr;
837         struct mntwalk *mw;
838         struct strace *s;
839
840         if (c->qid.type & QTDIR) {
841                 int nn;
842                 printd("procread: dir\n");
843                 nn = devdirread(c, va, n, 0, 0, procgen);
844                 printd("procread: %d\n", nn);
845                 return nn;
846         }
847
848         offset = off;
849         /* Some shit in proc doesn't need to grab the reference.  For strace, we
850          * already have the chan open, and all we want to do is read the queue,
851          * which exists because of our kref on it. */
852         switch (QID(c->qid)) {
853                 case Qstrace:
854                         s = c->aux;
855                         n = qread(s->q, va, n);
856                         return n;
857         }
858
859         if ((p = pid2proc(SLOT(c->qid))) == NULL)
860                 error(ESRCH, "%d: no such process", SLOT(c->qid));
861         if (p->pid != PID(c->qid)) {
862                 kref_put(&p->p_kref);
863                 error(ESRCH, "weird: p->pid is %d, PID(c->qid) is %d: mismatch",
864                       p->pid, PID(c->qid));
865         }
866         switch (QID(c->qid)) {
867                 default:
868                         kref_put(&p->p_kref);
869                         break;
870                 case Qstatus:{
871                                 /* the old code grew the stack and was hideous.
872                                  * status is not a high frequency operation; just malloc. */
873                                 char *buf = kmalloc(4096, MEM_WAIT);
874                                 char *s = buf, *e = buf + 4096;
875                                 int i;
876
877                                 s = seprintf(s, e,
878                                          "%8d %-*s %-10s %6d", p->pid, PROC_PROGNAME_SZ,
879                                          p->progname, procstate2str(p->state),
880                                          p->ppid);
881                                 if (p->strace)
882                                         s = seprintf(s, e, " %d trace users %d traced procs",
883                                                      kref_refcnt(&p->strace->users),
884                                                      kref_refcnt(&p->strace->procs));
885                                 kref_put(&p->p_kref);
886                                 i = readstr(off, va, n, buf);
887                                 kfree(buf);
888                                 return i;
889                         }
890
891                 case Qvmstatus:
892                         {
893                                 size_t buflen = 50 * 65 + 2;
894                                 char *buf = kmalloc(buflen, MEM_WAIT);
895                                 int i, offset;
896                                 offset = 0;
897                                 offset += snprintf(buf + offset, buflen - offset, "{\n");
898                                 for (i = 0; i < 65; i++) {
899                                         if (p->vmm.vmexits[i] != 0) {
900                                                 offset += snprintf(buf + offset, buflen - offset,
901                                                                    "\"%s\":\"%lld\",\n",
902                                                                    VMX_EXIT_REASON_NAMES[i],
903                                                                    p->vmm.vmexits[i]);
904                                         }
905                                 }
906                                 offset += snprintf(buf + offset, buflen - offset, "}\n");
907                                 kref_put(&p->p_kref);
908                                 n = readstr(off, va, n, buf);
909                                 kfree(buf);
910                                 return n;
911                         }
912                 case Qns:
913                         //qlock(&p->debug);
914                         if (waserror()) {
915                                 //qunlock(&p->debug);
916                                 kref_put(&p->p_kref);
917                                 nexterror();
918                         }
919                         if (p->pgrp == NULL || p->pid != PID(c->qid))
920                                 error(ESRCH, ERROR_FIXME);
921                         mw = c->aux;
922                         if (mw->cddone) {
923                                 poperror();
924                                 //qunlock(&p->debug);
925                                 kref_put(&p->p_kref);
926                                 return 0;
927                         }
928                         mntscan(mw, p);
929                         if (mw->mh == 0) {
930                                 mw->cddone = 1;
931                                 i = snprintf(va, n, "cd %s\n", p->dot->name->s);
932                                 poperror();
933                                 //qunlock(&p->debug);
934                                 kref_put(&p->p_kref);
935                                 return i;
936                         }
937                         int2flag(mw->cm->mflag, flag);
938                         if (strcmp(mw->cm->to->name->s, "#M") == 0) {
939                                 srv = srvname(mw->cm->to->mchan);
940                                 i = snprintf(va, n, "mount %s %s %s %s\n", flag,
941                                                          srv == NULL ? mw->cm->to->mchan->name->s : srv,
942                                                          mw->mh->from->name->s,
943                                                          mw->cm->spec ? mw->cm->spec : "");
944                                 kfree(srv);
945                         } else
946                                 i = snprintf(va, n, "bind %s %s %s\n", flag,
947                                                          mw->cm->to->name->s, mw->mh->from->name->s);
948                         poperror();
949                         //qunlock(&p->debug);
950                         kref_put(&p->p_kref);
951                         return i;
952         }
953         error(EINVAL, "QID %d did not match any QIDs for #proc", QID(c->qid));
954         return 0;       /* not reached */
955 }
956
957 static void mntscan(struct mntwalk *mw, struct proc *p)
958 {
959         struct pgrp *pg;
960         struct mount *t;
961         struct mhead *f;
962         int best, i, last, nxt;
963
964         pg = p->pgrp;
965         rlock(&pg->ns);
966
967         nxt = 0;
968         best = (int)(~0U >> 1); /* largest 2's complement int */
969
970         last = 0;
971         if (mw->mh)
972                 last = mw->cm->mountid;
973
974         for (i = 0; i < MNTHASH; i++) {
975                 for (f = pg->mnthash[i]; f; f = f->hash) {
976                         for (t = f->mount; t; t = t->next) {
977                                 if (mw->mh == 0 || (t->mountid > last && t->mountid < best)) {
978                                         mw->cm = t;
979                                         mw->mh = f;
980                                         best = mw->cm->mountid;
981                                         nxt = 1;
982                                 }
983                         }
984                 }
985         }
986         if (nxt == 0)
987                 mw->mh = 0;
988
989         runlock(&pg->ns);
990 }
991
992 static long procwrite(struct chan *c, void *va, long n, int64_t off)
993 {
994         ERRSTACK(2);
995
996         struct proc *p, *t;
997         int i, id, l;
998         char *args;
999         uintptr_t offset;
1000
1001         if (c->qid.type & QTDIR)
1002                 error(EISDIR, ERROR_FIXME);
1003
1004         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1005                 error(ESRCH, ERROR_FIXME);
1006
1007         if (waserror()) {
1008                 kref_put(&p->p_kref);
1009                 nexterror();
1010         }
1011         if (p->pid != PID(c->qid))
1012                 error(ESRCH, ERROR_FIXME);
1013
1014         offset = off;
1015
1016         switch (QID(c->qid)) {
1017 #if 0
1018                 case Qargs:
1019                         if (n == 0)
1020                                 error(EINVAL, ERROR_FIXME);
1021                         if (n >= sizeof buf - strlen(p->text) - 1)
1022                                 error(E2BIG, ERROR_FIXME);
1023                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1024                         args = kzmalloc(l + 1, MEM_WAIT);
1025                         if (args == NULL)
1026                                 error(ENOMEM, ERROR_FIXME);
1027                         memmove(args, buf, l);
1028                         args[l] = 0;
1029                         kfree(p->args);
1030                         p->nargs = l;
1031                         p->args = args;
1032                         p->setargs = 1;
1033                         break;
1034
1035                 case Qmem:
1036                         if (p->state != Stopped)
1037                                 error(EINVAL, ERROR_FIXME);
1038
1039                         n = procctlmemio(p, offset, n, va, 0);
1040                         break;
1041
1042                 case Qregs:
1043                         if (offset >= sizeof(Ureg))
1044                                 n = 0;
1045                         else if (offset + n > sizeof(Ureg))
1046                                 n = sizeof(Ureg) - offset;
1047                         if (p->dbgreg == 0)
1048                                 error(ENODATA, ERROR_FIXME);
1049                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1050                         break;
1051
1052                 case Qfpregs:
1053                         n = fpudevprocio(p, va, n, offset, 1);
1054                         break;
1055 #endif
1056                 case Qctl:
1057                         procctlreq(p, va, n);
1058                         break;
1059
1060                 /* this lets your write a marker into the data stream,
1061                  * which is a very powerful tool. */
1062                 case Qstrace:
1063                         assert(c->aux);
1064                         /* it is possible that the q hungup and is closed.  that would be
1065                          * the case if all of the procs closed and decref'd.  if the q is
1066                          * closed, qwrite() will throw an error. */
1067                         n = qwrite(((struct strace*)c->aux)->q, va, n);
1068                         break;
1069                 default:
1070                         error(EFAIL, "unknown qid %#llux in procwrite\n", c->qid.path);
1071         }
1072         poperror();
1073         kref_put(&p->p_kref);
1074         return n;
1075 }
1076
1077 struct dev procdevtab __devtab = {
1078         .name = "proc",
1079
1080         .reset = devreset,
1081         .init = procinit,
1082         .shutdown = devshutdown,
1083         .attach = procattach,
1084         .walk = procwalk,
1085         .stat = procstat,
1086         .open = procopen,
1087         .create = devcreate,
1088         .close = procclose,
1089         .read = procread,
1090         .bread = devbread,
1091         .write = procwrite,
1092         .bwrite = devbwrite,
1093         .remove = devremove,
1094         .wstat = procwstat,
1095         .power = devpower,
1096         .chaninfo = devchaninfo,
1097 };
1098
1099 #if 0
1100 static struct chan *proctext(struct chan *c, struct proc *p)
1101 {
1102         ERRSTACK(2);
1103         struct chan *tc;
1104         Image *i;
1105         Segment *s;
1106
1107         s = p->seg[TSEG];
1108         if (s == 0)
1109                 error(ENOENT, ERROR_FIXME);
1110         if (p->state == Dead)
1111                 error(ESRCH, ERROR_FIXME);
1112
1113         lock(s);
1114         i = s->image;
1115         if (i == 0) {
1116                 unlock(s);
1117                 error(ESRCH, ERROR_FIXME);
1118         }
1119         unlock(s);
1120
1121         lock(i);
1122         if (waserror()) {
1123                 unlock(i);
1124                 nexterror();
1125         }
1126
1127         tc = i->c;
1128         if (tc == 0)
1129                 error(ESRCH, ERROR_FIXME);
1130
1131         /* TODO: what do you want here?  you can't get a kref and have the new val
1132          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1133         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1134                 || tc->mode != OREAD) {
1135                 cclose(tc);
1136                 error(ESRCH, ERROR_FIXME);
1137         }
1138
1139         if (p->pid != PID(c->qid)) {
1140                 cclose(tc);
1141                 error(ESRCH, ERROR_FIXME);
1142         }
1143
1144         poperror();
1145         unlock(i);
1146
1147         return tc;
1148 }
1149
1150 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1151  * among other things, and we'll need to rewrite this for akaros */
1152 void procstopwait(struct proc *p, int ctl)
1153 {
1154         ERRSTACK(2);
1155         int pid;
1156
1157         if (p->pdbg)
1158                 error(EBUSY, ERROR_FIXME);
1159         if (procstopped(p) || p->state == Broken)
1160                 return;
1161
1162         if (ctl != 0)
1163                 p->procctl = ctl;
1164         p->pdbg = up;
1165         pid = p->pid;
1166         qunlock(&p->debug);
1167         current->psstate = "Stopwait";
1168         if (waserror()) {
1169                 p->pdbg = 0;
1170                 qlock(&p->debug);
1171                 nexterror();
1172         }
1173         rendez_sleep(&current->sleep, procstopped, p);
1174         poperror();
1175         qlock(&p->debug);
1176         if (p->pid != pid)
1177                 error(ESRCH, ERROR_FIXME);
1178 }
1179
1180 #endif
1181 static void procctlcloseone(struct proc *p, int fd)
1182 {
1183 // TODO: resolve this and sys_close
1184         struct file *file = get_file_from_fd(&p->open_files, fd);
1185         int retval = 0;
1186         printd("%s %d\n", __func__, fd);
1187         /* VFS */
1188         if (file) {
1189                 put_file_from_fd(&p->open_files, fd);
1190                 kref_put(&file->f_kref);        /* Drop the ref from get_file */
1191                 return;
1192         }
1193         /* 9ns, should also handle errors (bad FD, etc) */
1194         retval = sysclose(fd);
1195         return;
1196
1197         //sys_close(p, fd);
1198 }
1199
1200 void procctlclosefiles(struct proc *p, int all, int fd)
1201 {
1202         int i;
1203
1204         if (all)
1205                 for (i = 0; i < NR_FILE_DESC_MAX; i++)
1206                         procctlcloseone(p, i);
1207         else
1208                 procctlcloseone(p, fd);
1209 }
1210
1211 static void strace_shutdown(struct kref *a)
1212 {
1213         struct strace *strace = container_of(a, struct strace, procs);
1214         static const char base_msg[] = "Traced ~%lu syscs, Dropped %lu";
1215         size_t msg_len = NUMSIZE64 * 2 + sizeof(base_msg);
1216         char *msg = kmalloc(msg_len, 0);
1217
1218         if (msg)
1219                 snprintf(msg, msg_len, base_msg, strace->appx_nr_sysc,
1220                          atomic_read(&strace->nr_drops));
1221         qhangup(strace->q, msg);
1222         kfree(msg);
1223 }
1224
1225 static void strace_release(struct kref *a)
1226 {
1227         struct strace *strace = container_of(a, struct strace, users);
1228
1229         qfree(strace->q);
1230         kfree(strace);
1231 }
1232
1233 static void procctlreq(struct proc *p, char *va, int n)
1234 {
1235         ERRSTACK(1);
1236         int8_t irq_state = 0;
1237         int npc, pri, core;
1238         struct cmdbuf *cb;
1239         struct cmdtab *ct;
1240         int64_t time;
1241         char *e;
1242         struct strace *strace;
1243
1244         cb = parsecmd(va, n);
1245         if (waserror()) {
1246                 kfree(cb);
1247                 nexterror();
1248         }
1249
1250         ct = lookupcmd(cb, proccmd, ARRAY_SIZE(proccmd));
1251
1252         switch (ct->index) {
1253         case CMstraceall:
1254         case CMstraceme:
1255                 /* common allocation.  if we inherited, we might have one already */
1256                 if (!p->strace) {
1257                         strace = kzmalloc(sizeof(*p->strace), MEM_WAIT);
1258                         strace->q = qopen(65536, Qdropoverflow|Qcoalesce, NULL, NULL);
1259                         /* both of these refs are put when the proc is freed.  procs is for
1260                          * every process that has this p->strace.  users is procs + every
1261                          * user (e.g. from open()).
1262                          *
1263                          * it is possible to kref_put the procs kref in proc_destroy, which
1264                          * would make strace's job easier (no need to do an async wait on
1265                          * the child), and we wouldn't need to decref p in
1266                          * procread(Qstrace).  But the downside is that proc_destroy races
1267                          * with us here with the kref initialization. */
1268                         kref_init(&strace->procs, strace_shutdown, 1);
1269                         kref_init(&strace->users, strace_release, 1);
1270                         if (!atomic_cas_ptr((void**)&p->strace, 0, strace)) {
1271                                 /* someone else won the race and installed strace. */
1272                                 qfree(strace->q);
1273                                 kfree(strace);
1274                                 error(EAGAIN, "Concurrent strace init, try again");
1275                         }
1276                 }
1277                 break;
1278         }
1279
1280         /* actually do the command. */
1281         switch (ct->index) {
1282         case CMvmstart:
1283         case CMvmkill:
1284         default:
1285                 error(EFAIL, "Command not implemented");
1286                 break;
1287         case CMclose:
1288                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1289                 break;
1290         case CMclosefiles:
1291                 procctlclosefiles(p, 1, 0);
1292                 break;
1293 #if 0
1294                 we may want this.Let us pause a proc.case CMhang:p->hang = 1;
1295                 break;
1296 #endif
1297         case CMkill:
1298                 p = pid2proc(strtol(cb->f[1], 0, 0));
1299                 if (!p)
1300                         error(EFAIL, "No such proc\n");
1301
1302                 enable_irqsave(&irq_state);
1303                 proc_destroy(p);
1304                 disable_irqsave(&irq_state);
1305                 proc_decref(p);
1306                 /* this is a little ghetto. it's not fully free yet, but we are also
1307                  * slowing it down by messing with it, esp with the busy waiting on a
1308                  * hyperthreaded core. */
1309                 spin_on(p->env_cr3);
1310                 break;
1311         case CMvminit:
1312                 break;
1313         case CMstraceme:
1314                 p->strace_on = TRUE;
1315                 p->strace_inherit = FALSE;
1316                 break;
1317         case CMstraceall:
1318                 p->strace_on = TRUE;
1319                 p->strace_inherit = TRUE;
1320                 break;
1321         case CMstraceoff:
1322                 p->strace_on = FALSE;
1323                 p->strace_inherit = FALSE;
1324                 break;
1325         }
1326         poperror();
1327         kfree(cb);
1328 }
1329
1330 #if 0
1331 static int procstopped(void *a)
1332 {
1333         struct proc *p = a;
1334         return p->state == Stopped;
1335 }
1336
1337 static int
1338 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1339 {
1340         KMap *k;
1341         Pte *pte;
1342         Page *pg;
1343         Segment *s;
1344         uintptr_t soff, l;                      /* hmmmm */
1345         uint8_t *b;
1346         uintmem pgsz;
1347
1348         for (;;) {
1349                 s = seg(p, offset, 1);
1350                 if (s == 0)
1351                         error(EINVAL, ERROR_FIXME);
1352
1353                 if (offset + n >= s->top)
1354                         n = s->top - offset;
1355
1356                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1357                         s = txt2data(p, s);
1358
1359                 s->steal++;
1360                 soff = offset - s->base;
1361                 if (waserror()) {
1362                         s->steal--;
1363                         nexterror();
1364                 }
1365                 if (fixfault(s, offset, read, 0, s->color) == 0)
1366                         break;
1367                 poperror();
1368                 s->steal--;
1369         }
1370         poperror();
1371         pte = s->map[soff / PTEMAPMEM];
1372         if (pte == 0)
1373                 panic("procctlmemio");
1374         pgsz = m->pgsz[s->pgszi];
1375         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1376         if (pagedout(pg))
1377                 panic("procctlmemio1");
1378
1379         l = pgsz - (offset & (pgsz - 1));
1380         if (n > l)
1381                 n = l;
1382
1383         k = kmap(pg);
1384         if (waserror()) {
1385                 s->steal--;
1386                 kunmap(k);
1387                 nexterror();
1388         }
1389         b = (uint8_t *) VA(k);
1390         b += offset & (pgsz - 1);
1391         if (read == 1)
1392                 memmove(va, b, n);      /* This can fault */
1393         else
1394                 memmove(b, va, n);
1395         poperror();
1396         kunmap(k);
1397
1398         /* Ensure the process sees text page changes */
1399         if (s->flushme)
1400                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1401
1402         s->steal--;
1403
1404         if (read == 0)
1405                 p->newtlb = 1;
1406
1407         return n;
1408 }
1409
1410 static Segment *txt2data(struct proc *p, Segment * s)
1411 {
1412         int i;
1413         Segment *ps;
1414
1415         ps = newseg(SG_DATA, s->base, s->size);
1416         ps->image = s->image;
1417         kref_get(&ps->image->ref, 1);
1418         ps->fstart = s->fstart;
1419         ps->flen = s->flen;
1420         ps->flushme = 1;
1421
1422         qlock(&p->seglock);
1423         for (i = 0; i < NSEG; i++)
1424                 if (p->seg[i] == s)
1425                         break;
1426         if (i == NSEG)
1427                 panic("segment gone");
1428
1429         qunlock(&s->lk);
1430         putseg(s);
1431         qlock(&ps->lk);
1432         p->seg[i] = ps;
1433         qunlock(&p->seglock);
1434
1435         return ps;
1436 }
1437
1438 Segment *data2txt(Segment * s)
1439 {
1440         Segment *ps;
1441
1442         ps = newseg(SG_TEXT, s->base, s->size);
1443         ps->image = s->image;
1444         kref_get(&ps->image->ref, 1);
1445         ps->fstart = s->fstart;
1446         ps->flen = s->flen;
1447         ps->flushme = 1;
1448
1449         return ps;
1450 }
1451 #endif