Bring the proc device back.
[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
33 enum {
34         Qdir,
35         Qtrace,
36         Qtracepids,
37         Qns,
38         Qargs,
39         Qctl,
40         Qfd,
41         Qfpregs,
42         Qkregs,
43         Qmem,
44         Qnote,
45         Qnoteid,
46         Qnotepg,
47         Qproc,
48         Qregs,
49         Qsegment,
50         Qstatus,
51         Qtext,
52         Qwait,
53         Qprofile,
54         Qsyscall,
55         Qcore,
56 };
57
58 enum {
59         CMclose,
60         CMclosefiles,
61         CMfixedpri,
62         CMhang,
63         CMkill,
64         CMnohang,
65         CMnoswap,
66         CMpri,
67         CMprivate,
68         CMprofile,
69         CMstart,
70         CMstartstop,
71         CMstartsyscall,
72         CMstop,
73         CMwaitstop,
74         CMwired,
75         CMtrace,
76         /* real time */
77         CMperiod,
78         CMdeadline,
79         CMcost,
80         CMsporadic,
81         CMdeadlinenotes,
82         CMadmit,
83         CMextra,
84         CMexpel,
85         CMevent,
86         CMcore,
87 };
88
89 enum {
90         Nevents = 0x4000,
91         Emask = Nevents - 1,
92         Ntracedpids = 1024,
93 };
94
95 /* + 6 * 12 for extra NIX counters. */
96 #define STATSIZE        (2*KNAMELEN+12+9*12 +6*12)
97
98 /*
99  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
100  * particularly on shared servers.
101  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
102  */
103 struct dirtab procdir[] = {
104         {"args", {Qargs}, 0, 0660},
105         {"ctl", {Qctl}, 0, 0000},
106         {"fd", {Qfd}, 0, 0444},
107         {"fpregs", {Qfpregs}, 0, 0000},
108         //  {"kregs",   {Qkregs},   sizeof(Ureg),       0600},
109         {"mem", {Qmem}, 0, 0000},
110         {"note", {Qnote}, 0, 0000},
111         {"noteid", {Qnoteid}, 0, 0664},
112         {"notepg", {Qnotepg}, 0, 0000},
113         {"ns", {Qns}, 0, 0444},
114         {"proc", {Qproc}, 0, 0400},
115         //  {"regs",        {Qregs},    sizeof(Ureg),       0000},
116         {"segment", {Qsegment}, 0, 0444},
117         {"status", {Qstatus}, STATSIZE, 0444},
118         {"text", {Qtext}, 0, 0000},
119         {"wait", {Qwait}, 0, 0400},
120         {"profile", {Qprofile}, 0, 0400},
121         {"syscall", {Qsyscall}, 0, 0400},
122         {"core", {Qcore}, 0, 0444},
123 };
124
125 static
126 struct cmdtab proccmd[] = {
127         {CMclose, "close", 2},
128         {CMclosefiles, "closefiles", 1},
129         {CMfixedpri, "fixedpri", 2},
130         {CMhang, "hang", 1},
131         {CMnohang, "nohang", 1},
132         {CMnoswap, "noswap", 1},
133         {CMkill, "kill", 1},
134         {CMpri, "pri", 2},
135         {CMprivate, "private", 1},
136         {CMprofile, "profile", 1},
137         {CMstart, "start", 1},
138         {CMstartstop, "startstop", 1},
139         {CMstartsyscall, "startsyscall", 1},
140         {CMstop, "stop", 1},
141         {CMwaitstop, "waitstop", 1},
142         {CMwired, "wired", 2},
143         {CMtrace, "trace", 0},
144         {CMperiod, "period", 2},
145         {CMdeadline, "deadline", 2},
146         {CMcost, "cost", 2},
147         {CMsporadic, "sporadic", 1},
148         {CMdeadlinenotes, "deadlinenotes", 1},
149         {CMadmit, "admit", 1},
150         {CMextra, "extra", 1},
151         {CMexpel, "expel", 1},
152         {CMevent, "event", 1},
153         {CMcore, "core", 2},
154 };
155
156 /* Segment type from portdat.h */
157 static char *sname[] = { "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
158
159 /*
160  * struct qids are, in path:
161  *       5 bits of file type (qids above) (old comment said 4 here)
162  *      23 bits of process slot number + 1 (pid + 1 is stored)
163  *           in vers,
164  *      32 bits of pid, for consistency checking
165  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
166  */
167 #define QSHIFT  5       /* location in qid of proc slot # */
168 #define SLOTBITS 23     /* number of bits in the slot */
169 #define QIDMASK ((1<<QSHIFT)-1)
170 #define SLOTMASK        (((1<<SLOTBITS)-1) << QSHIFT)
171
172 #define QID(q)          ((((uint32_t)(q).path)&QIDMASK)>>0)
173 #define SLOT(q)         (((((uint32_t)(q).path)&SLOTMASK)>>QSHIFT)-1)
174 #define PID(q)          ((q).vers)
175 #define NOTEID(q)       ((q).vers)
176
177 static void procctlreq(struct proc *, char *, int);
178 static int procctlmemio(struct proc *, uintptr_t, int, void *, int);
179 //static struct chan*   proctext(struct chan*, struct proc*);
180 //static Segment* txt2data(struct proc*, Segment*);
181 //static int    procstopped(void*);
182 static void mntscan(struct mntwalk *, struct proc *);
183
184 //static Traceevent *tevents;
185 static char *tpids, *tpidsc, *tpidse;
186 static spinlock_t tlock;
187 static int topens;
188 static int tproduced, tconsumed;
189 //static void notrace(struct proc*, int, int64_t);
190
191 //void (*proctrace)(struct proc*, int, int64_t) = notrace;
192
193 #if 0
194 static void profclock(Ureg * ur, Timer *)
195 {
196         Tos *tos;
197
198         if (up == NULL || current->state != Running)
199                 return;
200
201         /* user profiling clock */
202         if (userureg(ur)) {
203                 tos = (Tos *) (USTKTOP - sizeof(Tos));
204                 tos->clock += TK2MS(1);
205                 segclock(userpc(ur));
206         }
207 }
208 #endif
209 static int
210 procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
211                 struct dir *dp)
212 {
213         struct qid qid;
214         struct proc *p;
215         char *ename;
216
217         int pid;
218         uint32_t path, perm, len;
219         if (s == DEVDOTDOT) {
220                 mkqid(&qid, Qdir, 0, QTDIR);
221                 devdir(c, qid, "#p", 0, eve, 0555, dp);
222                 return 1;
223         }
224
225         if (c->qid.path == Qdir) {
226                 if (s == 0) {
227                         strncpy(get_cur_genbuf(), "trace", GENBUF_SZ);
228                         mkqid(&qid, Qtrace, -1, QTFILE);
229                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
230                         return 1;
231                 }
232                 if (s == 1) {
233                         strncpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
234                         mkqid(&qid, Qtracepids, -1, QTFILE);
235                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
236                         return 1;
237                 }
238                 s -= 2;
239                 if (name != NULL) {
240                         /* ignore s and use name to find pid */
241                         pid = strtol(name, &ename, 10);
242                         if (pid <= 0 || ename[0] != '\0')
243                                 return -1;
244                         p = pid2proc(pid);
245                         if (!p)
246                                 return -1;
247                         /* Need to update s, so that it's the correct 'index' for our proc
248                          * (aka, the pid).  We use s later when making the qid. */
249                         s = pid;
250                 } else {
251                         /* This is a shitty iterator, and the list isn't guaranteed to give
252                          * you the same ordering twice in a row. (procs come and go). */
253                         p = pid_nth(s);
254                         if (!p)
255                                 return -1;
256                         pid = p->pid;
257                 }
258
259                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%u", pid);
260                 /*
261                  * String comparison is done in devwalk so
262                  * name must match its formatted pid.
263                  */
264                 if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
265                         printk("pid-name mismatch, name: %s, pid %d\n", name, pid);
266                         kref_put(&p->p_kref);
267                         return -1;
268                 }
269                 mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
270                 devdir(c, qid, get_cur_genbuf(), 0, p->user, DMDIR | 0555, dp);
271                 kref_put(&p->p_kref);
272                 return 1;
273         }
274         if (c->qid.path == Qtrace) {
275                 strncpy(get_cur_genbuf(), "trace", GENBUF_SZ);
276                 mkqid(&qid, Qtrace, -1, QTFILE);
277                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
278                 return 1;
279         }
280         if (c->qid.path == Qtracepids) {
281                 strncpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
282                 mkqid(&qid, Qtracepids, -1, QTFILE);
283                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
284                 return 1;
285         }
286         if (s >= ARRAY_SIZE(procdir))
287                 return -1;
288         if (tab)
289                 panic("procgen");
290
291         tab = &procdir[s];
292         /* path is everything other than the QID part.  Not sure from the orig code
293          * if they wanted just the pid part (SLOTMASK) or everything above QID */
294         path = c->qid.path & ~QIDMASK;  /* slot component */
295         if ((p = pid2proc(SLOT(c->qid))) == NULL)
296                 return -1;
297         perm = 0444 | tab->perm;
298 #if 0
299         if (perm == 0)
300                 perm = p->procmode;
301         else    /* just copy read bits */
302                 perm |= p->procmode & 0444;
303 #endif
304
305         len = tab->length;
306 #if 0
307         switch (QID(c->qid)) {
308                 case Qwait:
309                         len = p->nwait; /* incorrect size, but >0 means there's something to read */
310                         break;
311                 case Qprofile:
312                         q = p->seg[TSEG];
313                         if (q && q->profile) {
314                                 len = (q->top - q->base) >> LRESPROF;
315                                 len *= sizeof(*q->profile);
316                         }
317                         break;
318         }
319 #endif
320
321         mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
322         devdir(c, qid, tab->name, len, p->user, perm, dp);
323         kref_put(&p->p_kref);
324         return 1;
325 }
326
327 #if 0
328 static void notrace(struct proc *, Tevent, int64_t)
329 {
330 }
331
332 static spinlock_t tlck = SPINLOCK_INITIALIZER_IRQSAVE;
333
334 static void _proctrace(struct proc *p, Tevent etype, int64_t ts)
335 {
336         Traceevent *te;
337         int tp;
338
339         ilock(&tlck);
340         if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) {
341                 iunlock(&tlck);
342                 return;
343         }
344         tp = tproduced++;
345         iunlock(&tlck);
346
347         te = &tevents[tp & Emask];
348         te->pid = p->pid;
349         te->etype = etype;
350         if (ts == 0)
351                 te->time = todget(NULL);
352         else
353                 te->time = ts;
354         te->core = m->machno;
355 }
356
357 void proctracepid(struct proc *p)
358 {
359         if (p->trace == 1 && proctrace != notrace) {
360                 p->trace = 2;
361                 ilock(&tlck);
362                 tpidsc = seprint(tpidsc, tpidse, "%d %s\n", p->pid, p->text);
363                 iunlock(&tlck);
364         }
365 }
366
367 #endif
368 static void procinit(void)
369 {
370 #if 0
371         if (conf.nproc >= (SLOTMASK >> QSHIFT) - 1)
372                 printd("warning: too many procs for devproc\n");
373         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
374 #endif
375 }
376
377 static struct chan *procattach(char *spec)
378 {
379         return devattach('p', spec);
380 }
381
382 static struct walkqid *procwalk(struct chan *c, struct chan *nc, char **name,
383                                                                 int nname)
384 {
385         return devwalk(c, nc, name, nname, 0, 0, procgen);
386 }
387
388 static int
389 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);
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("proc: Qtrace: not yet");
427 #if 0
428                 if (omode != OREAD)
429                         error(Eperm);
430                 lock(&tlock);
431                 if (waserror()) {
432                         unlock(&tlock);
433                         nexterror();
434                 }
435                 if (topens > 0)
436                         error("already open");
437                 topens++;
438                 if (tevents == NULL) {
439                         tevents = (Traceevent *) kzmalloc(sizeof(Traceevent) * Nevents,
440                                                           KMALLOC_WAIT);
441                         if (tevents == NULL)
442                                 error(Enomem);
443                         tpids = kzmalloc(Ntracedpids * 20, KMALLOC_WAIT);
444                         if (tpids == NULL) {
445                                 kfree(tpids);
446                                 tpids = NULL;
447                                 error(Enomem);
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("Proc: Qtracepids: not yet");
466 #if 0
467                 if (omode != OREAD)
468                         error(Eperm);
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(Eprocdied);
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(Eprocdied);
486
487         omode = openmode(omode);
488
489         switch (QID(c->qid)) {
490                 case Qtext:
491                         error("notyet");
492 /*
493                         if (omode != OREAD)
494                                 error(Eperm);
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 != OREAD)
508                                 error(Eperm);
509                         break;
510
511                 case Qnote:
512 //                      if (p->privatemem)
513                                 error(Eperm);
514                         break;
515
516                 case Qmem:
517                 case Qctl:
518 //                      if (p->privatemem)
519                                 error(Eperm);
520                         //nonone(p);
521                         break;
522
523                 case Qargs:
524                 case Qnoteid:
525                 case Qstatus:
526                 case Qwait:
527                 case Qregs:
528                 case Qfpregs:
529                 case Qkregs:
530                 case Qsyscall:
531                 case Qcore:
532                         nonone(p);
533                         break;
534
535                 case Qns:
536                         if (omode != OREAD)
537                                 error(Eperm);
538                         c->aux = kzmalloc(sizeof(struct mntwalk), KMALLOC_WAIT);
539                         break;
540
541                 case Qnotepg:
542                         error("not yet");
543 #if 0
544                         nonone(p);
545                         pg = p->pgrp;
546                         if (pg == NULL)
547                                 error(Eprocdied);
548                         if (omode != OWRITE || pg->pgrpid == 1)
549                                 error(Eperm);
550                         c->pgrpid.path = pg->pgrpid + 1;
551                         c->pgrpid.vers = p->noteid;
552 #endif
553                         break;
554
555                 default:
556                         poperror();
557                         //qunlock(&p->debug);
558                         kref_put(&p->p_kref);
559                         printk("procopen %#llux\n", c->qid.path);
560                         error(Egreg);
561         }
562
563         /* Affix pid to qid */
564 //      if (p->state != Dead)
565                 c->qid.vers = p->pid;
566         /* make sure the process slot didn't get reallocated while we were playing */
567         //coherence();
568         /* TODO: think about what we really want here.  In akaros, we wouldn't have
569          * our pid changed like that. */
570         if (p->pid != pid)
571                 error(Eprocdied);
572
573         tc = devopen(c, omode, 0, 0, procgen);
574         poperror();
575         //qunlock(&p->debug);
576         kref_put(&p->p_kref);
577         return tc;
578 }
579
580 static int
581 procwstat(struct chan *c, uint8_t * db, int n)
582 {
583         ERRSTACK(2);
584         error("procwwstat: not yet");
585 #if 0
586         struct proc *p;
587         struct dir *d;
588
589         if (c->qid.type & QTDIR)
590                 error(Eperm);
591
592         if (QID(c->qid) == Qtrace)
593                 return devwstat(c, db, n);
594
595         if ((p = pid2proc(SLOT(c->qid))) == NULL)
596                 error(Eprocdied);
597         nonone(p);
598         d = NULL;
599         qlock(&p->debug);
600         if (waserror()) {
601                 qunlock(&p->debug);
602                 kref_put(&p->p_kref);
603                 kfree(d);
604                 nexterror();
605         }
606
607         if (p->pid != PID(c->qid))
608                 error(Eprocdied);
609
610         if (strcmp(current->user, p->user) != 0 && strcmp(current->user, eve) != 0)
611                 error(Eperm);
612
613         d = kzmalloc(sizeof(struct dir) + n, KMALLOC_WAIT);
614         n = convM2D(db, n, &d[0], (char *)&d[1]);
615         if (n == 0)
616                 error(Eshortstat);
617         if (!emptystr(d->uid) && strcmp(d->uid, p->user) != 0) {
618                 if (strcmp(current->user, eve) != 0)
619                         error(Eperm);
620                 else
621                         kstrdup(&p->user, d->uid);
622         }
623         if (d->mode != ~0UL)
624                 p->procmode = d->mode & 0777;
625
626         poperror();
627         qunlock(&p->debug);
628         kref_put(&p->p_kref);
629         kfree(d);
630
631         return n;
632 #endif
633 }
634
635 #if 0
636 static long procoffset(long offset, char *va, int *np)
637 {
638         if (offset > 0) {
639                 offset -= *np;
640                 if (offset < 0) {
641                         memmove(va, va + *np + offset, -offset);
642                         *np = -offset;
643                 } else
644                         *np = 0;
645         }
646         return offset;
647 }
648
649 static int procqidwidth(struct chan *c)
650 {
651         char buf[32];
652
653         return sprint(buf, "%lu", c->qid.vers);
654 }
655
656 int procfdprint(struct chan *c, int fd, int w, char *s, int ns)
657 {
658         int n;
659
660         if (w == 0)
661                 w = procqidwidth(c);
662         n = snprint(s, ns,
663                                 "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd,
664                                 &"r w rw"[(c->mode & 3) << 1], c->dev->dc, c->devno,
665                                 c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset,
666                                 c->name->s);
667         return n;
668 }
669
670 static int procfds(struct proc *p, char *va, int count, long offset)
671 {
672         ERRSTACK(2);
673         struct fgrp *f;
674         struct chan *c;
675         char buf[256];
676         int n, i, w, ww;
677         char *a;
678
679         /* print to buf to avoid holding fgrp lock while writing to user space */
680         if (count > sizeof buf)
681                 count = sizeof buf;
682         a = buf;
683
684         qlock(&p->debug);
685         f = p->fgrp;
686         if (f == NULL) {
687                 qunlock(&p->debug);
688                 return 0;
689         }
690         lock(f);
691         if (waserror()) {
692                 unlock(f);
693                 qunlock(&p->debug);
694                 nexterror();
695         }
696
697         n = readstr(0, a, count, p->dot->name->s);
698         n += snprint(a + n, count - n, "\n");
699         offset = procoffset(offset, a, &n);
700         /* compute width of qid.path */
701         w = 0;
702         for (i = 0; i <= f->maxfd; i++) {
703                 c = f->fd[i];
704                 if (c == NULL)
705                         continue;
706                 ww = procqidwidth(c);
707                 if (ww > w)
708                         w = ww;
709         }
710         for (i = 0; i <= f->maxfd; i++) {
711                 c = f->fd[i];
712                 if (c == NULL)
713                         continue;
714                 n += procfdprint(c, i, w, a + n, count - n);
715                 offset = procoffset(offset, a, &n);
716         }
717         poperror();
718         unlock(f);
719         qunlock(&p->debug);
720
721         /* copy result to user space, now that locks are released */
722         memmove(va, buf, n);
723
724         return n;
725 }
726 #endif
727 static void procclose(struct chan *c)
728 {
729         if (QID(c->qid) == Qtrace) {
730                 spin_lock(&tlock);
731                 if (topens > 0)
732                         topens--;
733                 /* ??
734                    if(topens == 0)
735                    proctrace = notrace;
736                  */
737                 spin_unlock(&tlock);
738         }
739         if (QID(c->qid) == Qns && c->aux != 0)
740                 kfree(c->aux);
741 }
742
743 void int2flag(int flag, char *s)
744 {
745         if (flag == 0) {
746                 *s = '\0';
747                 return;
748         }
749         *s++ = '-';
750         if (flag & MAFTER)
751                 *s++ = 'a';
752         if (flag & MBEFORE)
753                 *s++ = 'b';
754         if (flag & MCREATE)
755                 *s++ = 'c';
756         if (flag & MCACHE)
757                 *s++ = 'C';
758         *s = '\0';
759 }
760
761 #if 0
762 static char *argcpy(char *s, char *p)
763 {
764         char *t, *tp, *te;
765         int n;
766
767         n = p - s;
768         if (n > 128)
769                 n = 128;
770         if (n <= 0) {
771                 t = kzmalloc(1, KMALLOC_WAIT);
772                 *t = 0;
773                 return t;
774         }
775         t = kzmalloc(n, KMALLOC_WAIT);
776         tp = t;
777         te = t + n;
778
779         while (tp + 1 < te) {
780                 for (p--; p > s && p[-1] != 0; p--) ;
781                 tp = seprint(tp, te, "%q ", p);
782                 if (p == s)
783                         break;
784         }
785         if (*tp == ' ')
786                 *tp = 0;
787         return t;
788 }
789
790 static int procargs(struct proc *p, char *buf, int nbuf)
791 {
792         char *s;
793
794         if (p->setargs == 0) {
795                 s = argcpy(p->args, p->args + p->nargs);
796                 kfree(p->args);
797                 p->nargs = strlen(s);
798                 p->args = s;
799                 p->setargs = 1;
800         }
801         return snprint(buf, nbuf, "%s", p->args);
802 }
803
804 static int eventsavailable(void *)
805 {
806         return tproduced > tconsumed;
807 }
808 #endif
809 static long
810 procread(struct chan *c, void *va, long n, int64_t off)
811 {
812         ERRSTACK(5);
813         struct proc *p;
814         long l, r;
815         int i, j, navail, pid, rsize;
816         char flag[10], *sps, *srv, statbuf[512];
817         uintptr_t offset, u;
818         int tesz;
819         uint8_t *rptr;
820         struct mntwalk *mw;
821 #if 0
822         Mach *ac, *wired;
823         Waitq *wq;
824         Ureg kur;
825         Confmem *cm;
826         Segment *sg, *s;
827 #endif
828         if (c->qid.type & QTDIR){
829                 int nn;
830                 printd("procread: dir\n");
831                 nn =  devdirread(c, va, n, 0, 0, procgen);
832                 printd("procread: %d\n", nn);
833                 return nn;
834         }
835
836
837         offset = off;
838 #if 0
839         if (QID(c->qid) == Qtrace) {
840                 if (!eventsavailable(NULL))
841                         return 0;
842
843                 rptr = va;
844                 tesz = BIT32SZ + BIT32SZ + BIT64SZ + BIT32SZ;
845                 navail = tproduced - tconsumed;
846                 if (navail > n / tesz)
847                         navail = n / tesz;
848                 while (navail > 0) {
849                         PBIT32(rptr, tevents[tconsumed & Emask].pid);
850                         rptr += BIT32SZ;
851                         PBIT32(rptr, tevents[tconsumed & Emask].etype);
852                         rptr += BIT32SZ;
853                         PBIT64(rptr, tevents[tconsumed & Emask].time);
854                         rptr += BIT64SZ;
855                         PBIT32(rptr, tevents[tconsumed & Emask].core);
856                         rptr += BIT32SZ;
857                         tconsumed++;
858                         navail--;
859                 }
860                 return rptr - (uint8_t *) va;
861         }
862
863         if (QID(c->qid) == Qtracepids)
864                 if (tpids == NULL)
865                         return 0;
866                 else
867                         return readstr(off, va, n, tpids);
868 #endif
869         if ((p = pid2proc(SLOT(c->qid))) == NULL)
870                 error(Eprocdied);
871         if (p->pid != PID(c->qid)) {
872                 kref_put(&p->p_kref);
873                 error(Eprocdied);
874         }
875         switch (QID(c->qid)) {
876                 default:
877                         kref_put(&p->p_kref);
878                         break;
879 #if 0
880 #warning check refcnting in here
881                 case Qargs:
882                         qlock(&p->debug);
883                         j = procargs(p, current->genbuf, sizeof current->genbuf);
884                         qunlock(&p->debug);
885                         kref_put(&p->p_kref);
886                         if (offset >= j)
887                                 return 0;
888                         if (offset + n > j)
889                                 n = j - offset;
890                         memmove(va, &current->genbuf[offset], n);
891                         return n;
892
893                 case Qsyscall:
894                         if (p->syscalltrace == NULL)
895                                 return 0;
896                         return readstr(offset, va, n, p->syscalltrace);
897
898                 case Qcore:
899                         i = 0;
900                         ac = p->ac;
901                         wired = p->wired;
902                         if (ac != NULL)
903                                 i = ac->machno;
904                         else if (wired != NULL)
905                                 i = wired->machno;
906                         snprint(statbuf, sizeof statbuf, "%d\n", i);
907                         return readstr(offset, va, n, statbuf);
908
909                 case Qmem:
910                         if (offset < KZERO
911                                 || (offset >= USTKTOP - USTKSIZE && offset < USTKTOP)) {
912                                 r = procctlmemio(p, offset, n, va, 1);
913                                 kref_put(&p->p_kref);
914                                 return r;
915                         }
916
917                         if (!iseve()) {
918                                 kref_put(&p->p_kref);
919                                 error(Eperm);
920                         }
921
922                         /* validate kernel addresses */
923                         if (offset < PTR2UINT(end)) {
924                                 if (offset + n > PTR2UINT(end))
925                                         n = PTR2UINT(end) - offset;
926                                 memmove(va, UINT2PTR(offset), n);
927                                 kref_put(&p->p_kref);
928                                 return n;
929                         }
930                         for (i = 0; i < nelem(conf.mem); i++) {
931                                 cm = &conf.mem[i];
932                                 /* klimit-1 because klimit might be zero! */
933                                 if (cm->kbase <= offset && offset <= cm->klimit - 1) {
934                                         if (offset + n >= cm->klimit - 1)
935                                                 n = cm->klimit - offset;
936                                         memmove(va, UINT2PTR(offset), n);
937                                         kref_put(&p->p_kref);
938                                         return n;
939                                 }
940                         }
941                         kref_put(&p->p_kref);
942                         error(Ebadarg);
943
944                 case Qprofile:
945                         s = p->seg[TSEG];
946                         if (s == 0 || s->profile == 0)
947                                 error("profile is off");
948                         i = (s->top - s->base) >> LRESPROF;
949                         i *= sizeof(*s->profile);
950                         if (offset >= i) {
951                                 kref_put(&p->p_kref);
952                                 return 0;
953                         }
954                         if (offset + n > i)
955                                 n = i - offset;
956                         memmove(va, ((char *)s->profile) + offset, n);
957                         kref_put(&p->p_kref);
958                         return n;
959
960                 case Qnote:
961                         qlock(&p->debug);
962                         if (waserror()) {
963                                 qunlock(&p->debug);
964                                 kref_put(&p->p_kref);
965                                 nexterror();
966                         }
967                         if (p->pid != PID(c->qid))
968                                 error(Eprocdied);
969                         if (n < 1)      /* must accept at least the '\0' */
970                                 error(Etoosmall);
971                         if (p->nnote == 0)
972                                 n = 0;
973                         else {
974                                 i = strlen(p->note[0].msg) + 1;
975                                 if (i > n)
976                                         i = n;
977                                 rptr = va;
978                                 memmove(rptr, p->note[0].msg, i);
979                                 rptr[i - 1] = '\0';
980                                 p->nnote--;
981                                 memmove(p->note, p->note + 1, p->nnote * sizeof(Note));
982                                 n = i;
983                         }
984                         if (p->nnote == 0)
985                                 p->notepending = 0;
986                         poperror();
987                         qunlock(&p->debug);
988                         kref_put(&p->p_kref);
989                         return n;
990
991                 case Qproc:
992                         if (offset >= sizeof(struct proc)) {
993                                 kref_put(&p->p_kref);
994                                 return 0;
995                         }
996                         if (offset + n > sizeof(struct proc))
997                                 n = sizeof(struct proc) - offset;
998                         memmove(va, ((char *)p) + offset, n);
999                         kref_put(&p->p_kref);
1000                         return n;
1001
1002                 case Qregs:
1003                         rptr = (uint8_t *) p->dbgreg;
1004                         rsize = sizeof(Ureg);
1005 regread:
1006                         if (rptr == 0) {
1007                                 kref_put(&p->p_kref);
1008                                 error(Enoreg);
1009                         }
1010                         if (offset >= rsize) {
1011                                 kref_put(&p->p_kref);
1012                                 return 0;
1013                         }
1014                         if (offset + n > rsize)
1015                                 n = rsize - offset;
1016                         memmove(va, rptr + offset, n);
1017                         kref_put(&p->p_kref);
1018                         return n;
1019
1020                 case Qkregs:
1021                         memset(&kur, 0, sizeof(Ureg));
1022                         setkernur(&kur, p);
1023                         rptr = (uint8_t *) & kur;
1024                         rsize = sizeof(Ureg);
1025                         goto regread;
1026
1027                 case Qfpregs:
1028                         r = fpudevprocio(p, va, n, offset, 0);
1029                         kref_put(&p->p_kref);
1030                         return r;
1031
1032                 case Qstatus:
1033                         if (offset >= STATSIZE) {
1034                                 kref_put(&p->p_kref);
1035                                 return 0;
1036                         }
1037                         if (offset + n > STATSIZE)
1038                                 n = STATSIZE - offset;
1039
1040                         sps = p->psstate;
1041                         if (sps == 0)
1042                                 sps = statename[p->state];
1043                         memset(statbuf, ' ', sizeof statbuf);
1044                         j = 2 * KNAMELEN + 12;
1045                         snprint(statbuf, j + 1, "%-*.*s%-*.*s%-12.11s",
1046                                         KNAMELEN, KNAMELEN - 1, p->text,
1047                                         KNAMELEN, KNAMELEN - 1, p->user, sps);
1048
1049                         for (i = 0; i < 6; i++) {
1050                                 l = p->time[i];
1051                                 if (i == TReal)
1052                                         l = sys->ticks - l;
1053                                 l = TK2MS(l);
1054                                 readnum(0, statbuf + j + NUMSIZE * i, NUMSIZE, l, NUMSIZE);
1055                         }
1056                         /* ignore stack, which is mostly non-existent */
1057                         u = 0;
1058                         for (i = 1; i < NSEG; i++) {
1059                                 s = p->seg[i];
1060                                 if (s)
1061                                         u += s->top - s->base;
1062                         }
1063                         readnum(0, statbuf + j + NUMSIZE * 6, NUMSIZE, u >> 10u, NUMSIZE);      /* wrong size */
1064                         readnum(0, statbuf + j + NUMSIZE * 7, NUMSIZE, p->basepri, NUMSIZE);
1065                         readnum(0, statbuf + j + NUMSIZE * 8, NUMSIZE, p->priority,
1066                                         NUMSIZE);
1067
1068                         /*
1069                          * NIX: added # of traps, syscalls, and iccs
1070                          */
1071                         readnum(0, statbuf + j + NUMSIZE * 9, NUMSIZE, p->ntrap, NUMSIZE);
1072                         readnum(0, statbuf + j + NUMSIZE * 10, NUMSIZE, p->nintr, NUMSIZE);
1073                         readnum(0, statbuf + j + NUMSIZE * 11, NUMSIZE, p->nsyscall,
1074                                         NUMSIZE);
1075                         readnum(0, statbuf + j + NUMSIZE * 12, NUMSIZE, p->nicc, NUMSIZE);
1076                         readnum(0, statbuf + j + NUMSIZE * 13, NUMSIZE, p->nactrap,
1077                                         NUMSIZE);
1078                         readnum(0, statbuf + j + NUMSIZE * 14, NUMSIZE, p->nacsyscall,
1079                                         NUMSIZE);
1080                         memmove(va, statbuf + offset, n);
1081                         kref_put(&p->p_kref);
1082                         return n;
1083
1084                 case Qsegment:
1085                         j = 0;
1086                         for (i = 0; i < NSEG; i++) {
1087                                 sg = p->seg[i];
1088                                 if (sg == 0)
1089                                         continue;
1090                                 j += sprint(statbuf + j, "%-6s %c%c %p %p %4d\n",
1091                                                         sname[sg->type & SG_TYPE],
1092                                                         sg->type & SG_RONLY ? 'R' : ' ',
1093                                                         sg->profile ? 'P' : ' ',
1094                                                         sg->base, sg->top, sg->ref);
1095                         }
1096                         kref_put(&p->p_kref);
1097                         if (offset >= j)
1098                                 return 0;
1099                         if (offset + n > j)
1100                                 n = j - offset;
1101                         if (n == 0 && offset == 0)
1102                                 exhausted("segments");
1103                         memmove(va, &statbuf[offset], n);
1104                         return n;
1105
1106                 case Qwait:
1107                         if (!canqlock(&p->qwaitr)) {
1108                                 kref_put(&p->p_kref);
1109                                 error(Einuse);
1110                         }
1111
1112                         if (waserror()) {
1113                                 qunlock(&p->qwaitr);
1114                                 kref_put(&p->p_kref);
1115                                 nexterror();
1116                         }
1117
1118                         lock(&p->exl);
1119                         if (up == p && p->nchild == 0 && p->waitq == 0) {
1120                                 unlock(&p->exl);
1121                                 error(Enochild);
1122                         }
1123                         pid = p->pid;
1124                         while (p->waitq == 0) {
1125                                 unlock(&p->exl);
1126                                 rendez_sleep(&p->waitr, haswaitq, p);
1127                                 if (p->pid != pid)
1128                                         error(Eprocdied);
1129                                 lock(&p->exl);
1130                         }
1131                         wq = p->waitq;
1132                         p->waitq = wq->next;
1133                         p->nwait--;
1134                         unlock(&p->exl);
1135
1136                         poperror();
1137                         qunlock(&p->qwaitr);
1138                         kref_put(&p->p_kref);
1139                         n = snprint(va, n, "%d %lu %lud %lud %q",
1140                                                 wq->w.pid,
1141                                                 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
1142                                                 wq->w.msg);
1143                         kfree(wq);
1144                         return n;
1145 #endif
1146                 case Qns:
1147                         //qlock(&p->debug);
1148                         if (waserror()) {
1149                                 //qunlock(&p->debug);
1150                                 kref_put(&p->p_kref);
1151                                 nexterror();
1152                         }
1153                         if (p->pgrp == NULL || p->pid != PID(c->qid))
1154                                 error(Eprocdied);
1155                         mw = c->aux;
1156                         if (mw->cddone) {
1157                                 poperror();
1158                                 //qunlock(&p->debug);
1159                                 kref_put(&p->p_kref);
1160                                 return 0;
1161                         }
1162                         mntscan(mw, p);
1163                         if (mw->mh == 0) {
1164                                 mw->cddone = 1;
1165                                 i = snprintf(va, n, "cd %s\n", p->dot->name->s);
1166                                 poperror();
1167                                 //qunlock(&p->debug);
1168                                 kref_put(&p->p_kref);
1169                                 return i;
1170                         }
1171                         int2flag(mw->cm->mflag, flag);
1172                         if (strcmp(mw->cm->to->name->s, "#M") == 0) {
1173                                 srv = srvname(mw->cm->to->mchan);
1174                                 i = snprintf(va, n, "mount %s %s %s %s\n", flag,
1175                                                         srv == NULL ? mw->cm->to->mchan->name->s : srv,
1176                                                         mw->mh->from->name->s,
1177                                                         mw->cm->spec ? mw->cm->spec : "");
1178                                 kfree(srv);
1179                         } else
1180                                 i = snprintf(va, n, "bind %s %s %s\n", flag,
1181                                                         mw->cm->to->name->s, mw->mh->from->name->s);
1182                         poperror();
1183                         //qunlock(&p->debug);
1184                         kref_put(&p->p_kref);
1185                         return i;
1186 #if 0
1187                 case Qnoteid:
1188                         r = readnum(offset, va, n, p->noteid, NUMSIZE);
1189                         kref_put(&p->p_kref);
1190                         return r;
1191                 case Qfd:
1192                         r = procfds(p, va, n, offset);
1193                         kref_put(&p->p_kref);
1194                         return r;
1195 #endif
1196         }
1197
1198         error(Egreg);
1199         return 0;       /* not reached */
1200 }
1201
1202 static void mntscan(struct mntwalk * mw, struct proc *p)
1203 {
1204         struct pgrp *pg;
1205         struct mount *t;
1206         struct mhead *f;
1207         int best, i, last, nxt;
1208
1209         pg = p->pgrp;
1210         rlock(&pg->ns);
1211
1212         nxt = 0;
1213         best = (int)(~0U >> 1); /* largest 2's complement int */
1214
1215         last = 0;
1216         if (mw->mh)
1217                 last = mw->cm->mountid;
1218
1219         for (i = 0; i < MNTHASH; i++) {
1220                 for (f = pg->mnthash[i]; f; f = f->hash) {
1221                         for (t = f->mount; t; t = t->next) {
1222                                 if (mw->mh == 0 || (t->mountid > last && t->mountid < best)) {
1223                                         mw->cm = t;
1224                                         mw->mh = f;
1225                                         best = mw->cm->mountid;
1226                                         nxt = 1;
1227                                 }
1228                         }
1229                 }
1230         }
1231         if (nxt == 0)
1232                 mw->mh = 0;
1233
1234         runlock(&pg->ns);
1235 }
1236
1237 static long
1238 procwrite(struct chan *c, void *va, long n, int64_t off)
1239 {
1240         ERRSTACK(2);
1241         error("procwrite: not yet");
1242         return 0;
1243 #if 0
1244         struct proc *p, *t;
1245         int i, id, l;
1246         char *args, buf[ERRMAX];
1247         uintptr_t offset;
1248
1249         if (c->qid.type & QTDIR)
1250                 error(Eisdir);
1251
1252         /* Use the remembered noteid in the channel rather
1253          * than the process pgrpid
1254          */
1255         if (QID(c->qid) == Qnotepg) {
1256                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1257                 return n;
1258         }
1259
1260         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1261                 error(Eprocdied);
1262
1263         qlock(&p->debug);
1264         if (waserror()) {
1265                 qunlock(&p->debug);
1266                 kref_put(&p->p_kref);
1267                 nexterror();
1268         }
1269         if (p->pid != PID(c->qid))
1270                 error(Eprocdied);
1271
1272         offset = off;
1273
1274         switch (QID(c->qid)) {
1275                 case Qargs:
1276                         if (n == 0)
1277                                 error(Eshort);
1278                         if (n >= sizeof buf - strlen(p->text) - 1)
1279                                 error(Etoobig);
1280                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1281                         args = kzmalloc(l + 1, KMALLOC_WAIT);
1282                         if (args == NULL)
1283                                 error(Enomem);
1284                         memmove(args, buf, l);
1285                         args[l] = 0;
1286                         kfree(p->args);
1287                         p->nargs = l;
1288                         p->args = args;
1289                         p->setargs = 1;
1290                         break;
1291
1292                 case Qmem:
1293                         if (p->state != Stopped)
1294                                 error(Ebadctl);
1295
1296                         n = procctlmemio(p, offset, n, va, 0);
1297                         break;
1298
1299                 case Qregs:
1300                         if (offset >= sizeof(Ureg))
1301                                 n = 0;
1302                         else if (offset + n > sizeof(Ureg))
1303                                 n = sizeof(Ureg) - offset;
1304                         if (p->dbgreg == 0)
1305                                 error(Enoreg);
1306                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1307                         break;
1308
1309                 case Qfpregs:
1310                         n = fpudevprocio(p, va, n, offset, 1);
1311                         break;
1312
1313                 case Qctl:
1314                         procctlreq(p, va, n);
1315                         break;
1316
1317                 case Qnote:
1318                         if (p->kp)
1319                                 error(Eperm);
1320                         if (n >= ERRMAX - 1)
1321                                 error(Etoobig);
1322                         memmove(buf, va, n);
1323                         buf[n] = 0;
1324                         if (!postnote(p, 0, buf, NUser))
1325                                 error("note not posted");
1326                         break;
1327                 case Qnoteid:
1328                         id = atoi(va);
1329                         if (id == p->pid) {
1330                                 p->noteid = id;
1331                                 break;
1332                         }
1333                         /* Careful here, check that you know what the iterator is doing */
1334                         for (i = 0; (t = pid_nth(i)) != NULL; i++) {
1335                                 if (t->state == Dead || t->noteid != id) {
1336                                         kref_put(&p->p_kref);
1337                                         continue;
1338                                 }
1339                                 if (strcmp(p->user, t->user) != 0) {
1340                                         kref_put(&p->p_kref);
1341                                         error(Eperm);
1342                                 }
1343                                 kref_put(&p->p_kref);
1344                                 p->noteid = id;
1345                                 break;
1346                         }
1347                         if (p->noteid != id)
1348                                 error(Ebadarg);
1349                         break;
1350                 default:
1351                         poperror();
1352                         qunlock(&p->debug);
1353                         kref_put(&p->p_kref);
1354                         pprint("unknown qid %#llux in procwrite\n", c->qid.path);
1355                         error(Egreg);
1356         }
1357         poperror();
1358         qunlock(&p->debug);
1359         kref_put(&p->p_kref);
1360         return n;
1361 #endif
1362 }
1363
1364 struct dev procdevtab __devtab = {
1365         'p',
1366         "proc",
1367
1368         devreset,
1369         procinit,
1370         devshutdown,
1371         procattach,
1372         procwalk,
1373         procstat,
1374         procopen,
1375         devcreate,
1376         procclose,
1377         procread,
1378         devbread,
1379         procwrite,
1380         devbwrite,
1381         devremove,
1382         procwstat,
1383         devpower,
1384         devchaninfo,
1385 };
1386
1387 #if 0
1388 static struct chan *proctext(struct chan *c, struct proc *p)
1389 {
1390         ERRSTACK(2);
1391         struct chan *tc;
1392         Image *i;
1393         Segment *s;
1394
1395         s = p->seg[TSEG];
1396         if (s == 0)
1397                 error(Enonexist);
1398         if (p->state == Dead)
1399                 error(Eprocdied);
1400
1401         lock(s);
1402         i = s->image;
1403         if (i == 0) {
1404                 unlock(s);
1405                 error(Eprocdied);
1406         }
1407         unlock(s);
1408
1409         lock(i);
1410         if (waserror()) {
1411                 unlock(i);
1412                 nexterror();
1413         }
1414
1415         tc = i->c;
1416         if (tc == 0)
1417                 error(Eprocdied);
1418
1419         /* TODO: what do you want here?  you can't get a kref and have the new val
1420          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1421         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1422                 || tc->mode != OREAD) {
1423                 cclose(tc);
1424                 error(Eprocdied);
1425         }
1426
1427         if (p->pid != PID(c->qid)) {
1428                 cclose(tc);
1429                 error(Eprocdied);
1430         }
1431
1432         poperror();
1433         unlock(i);
1434
1435         return tc;
1436 }
1437
1438 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1439  * among other things, and we'll need to rewrite this for akaros */
1440 void procstopwait(struct proc *p, int ctl)
1441 {
1442         ERRSTACK(2);
1443         int pid;
1444
1445         if (p->pdbg)
1446                 error(Einuse);
1447         if (procstopped(p) || p->state == Broken)
1448                 return;
1449
1450         if (ctl != 0)
1451                 p->procctl = ctl;
1452         p->pdbg = up;
1453         pid = p->pid;
1454         qunlock(&p->debug);
1455         current->psstate = "Stopwait";
1456         if (waserror()) {
1457                 p->pdbg = 0;
1458                 qlock(&p->debug);
1459                 nexterror();
1460         }
1461         rendez_sleep(&current->sleep, procstopped, p);
1462         poperror();
1463         qlock(&p->debug);
1464         if (p->pid != pid)
1465                 error(Eprocdied);
1466 }
1467
1468 static void procctlcloseone(struct proc *p, struct fgrp *f, int fd)
1469 {
1470         struct chan *c;
1471
1472         c = f->fd[fd];
1473         if (c == NULL)
1474                 return;
1475         f->fd[fd] = NULL;
1476         unlock(f);
1477         qunlock(&p->debug);
1478         cclose(c);
1479         qlock(&p->debug);
1480         lock(f);
1481 }
1482
1483 void procctlclosefiles(struct proc *p, int all, int fd)
1484 {
1485         int i;
1486         struct fgrp *f;
1487
1488         f = p->fgrp;
1489         if (f == NULL)
1490                 error(Eprocdied);
1491
1492         lock(f);
1493         f->ref++;
1494         if (all)
1495                 for (i = 0; i < f->maxfd; i++)
1496                         procctlcloseone(p, f, i);
1497         else
1498                 procctlcloseone(p, f, fd);
1499         unlock(f);
1500         closefgrp(f);
1501 }
1502
1503 static char *parsetime(int64_t * rt, char *s)
1504 {
1505         uint64_t ticks;
1506         uint32_t l;
1507         char *e, *p;
1508         static int p10[] =
1509                 { 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
1510
1511         if (s == NULL)
1512                 return ("missing value");
1513         ticks = strtoul(s, &e, 10);
1514         if (*e == '.') {
1515                 p = e + 1;
1516                 l = strtoul(p, &e, 10);
1517                 if (e - p > nelem(p10))
1518                         return "too many digits after decimal point";
1519                 if (e - p == 0)
1520                         return "ill-formed number";
1521                 l *= p10[e - p - 1];
1522         } else
1523                 l = 0;
1524         if (*e == '\0' || strcmp(e, "s") == 0) {
1525                 ticks = 1000000000 * ticks + l;
1526         } else if (strcmp(e, "ms") == 0) {
1527                 ticks = 1000000 * ticks + l / 1000;
1528         } else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0) {
1529                 ticks = 1000 * ticks + l / 1000000;
1530         } else if (strcmp(e, "ns") != 0)
1531                 return "unrecognized unit";
1532         *rt = ticks;
1533         return NULL;
1534 }
1535
1536 static void procctlreq(struct proc *p, char *va, int n)
1537 {
1538         ERRSTACK(2);
1539         Segment *s;
1540         int npc, pri, core;
1541         struct cmdbuf *cb;
1542         struct cmdtab *ct;
1543         int64_t time;
1544         char *e;
1545
1546         if (p->kp)      /* no ctl requests to kprocs */
1547                 error(Eperm);
1548
1549         cb = parsecmd(va, n);
1550         if (waserror()) {
1551                 kfree(cb);
1552                 nexterror();
1553         }
1554
1555         ct = lookupcmd(cb, proccmd, nelem(proccmd));
1556
1557         switch (ct->index) {
1558                 case CMclose:
1559                         procctlclosefiles(p, 0, atoi(cb->f[1]));
1560                         break;
1561                 case CMclosefiles:
1562                         procctlclosefiles(p, 1, 0);
1563                         break;
1564                 case CMhang:
1565                         p->hang = 1;
1566                         break;
1567                 case CMkill:
1568                         switch (p->state) {
1569                                 case Broken:
1570                                         unbreak(p);
1571                                         break;
1572                                 case Stopped:
1573                                 case Semdown:
1574                                         p->procctl = struct proc_exitme;
1575                                         postnote(p, 0, "sys: killed", NExit);
1576                                         ready(p);
1577                                         break;
1578                                 default:
1579                                         p->procctl = struct proc_exitme;
1580                                         postnote(p, 0, "sys: killed", NExit);
1581                         }
1582                         break;
1583                 case CMnohang:
1584                         p->hang = 0;
1585                         break;
1586                 case CMnoswap:
1587                         p->noswap = 1;
1588                         break;
1589                 case CMpri:
1590                         pri = atoi(cb->f[1]);
1591                         if (pri > PriNormal && !iseve())
1592                                 error(Eperm);
1593                         procpriority(p, pri, 0);
1594                         break;
1595                 case CMfixedpri:
1596                         pri = atoi(cb->f[1]);
1597                         if (pri > PriNormal && !iseve())
1598                                 error(Eperm);
1599                         procpriority(p, pri, 1);
1600                         break;
1601                 case CMprivate:
1602                         p->privatemem = 1;
1603                         break;
1604                 case CMprofile:
1605                         s = p->seg[TSEG];
1606                         if (s == 0 || (s->type & SG_TYPE) != SG_TEXT)
1607                                 error(Ebadctl);
1608                         if (s->profile != 0)
1609                                 kfree(s->profile);
1610                         npc = (s->top - s->base) >> LRESPROF;
1611                         s->profile = kzmalloc(npc * sizeof(*s->profile), KMALLOC_WAIT);
1612                         if (s->profile == 0)
1613                                 error(Enomem);
1614                         break;
1615                 case CMstart:
1616                         if (p->state != Stopped)
1617                                 error(Ebadctl);
1618                         ready(p);
1619                         break;
1620                 case CMstartstop:
1621                         if (p->state != Stopped)
1622                                 error(Ebadctl);
1623                         p->procctl = struct proc_traceme;
1624                         ready(p);
1625                         procstopwait(p, struct proc_traceme);
1626                         break;
1627                 case CMstartsyscall:
1628                         if (p->state != Stopped)
1629                                 error(Ebadctl);
1630                         p->procctl = struct proc_tracesyscall;
1631                         ready(p);
1632                         procstopwait(p, struct proc_tracesyscall);
1633                         break;
1634                 case CMstop:
1635                         procstopwait(p, struct proc_stopme);
1636                         break;
1637                 case CMwaitstop:
1638                         procstopwait(p, 0);
1639                         break;
1640                 case CMwired:
1641                         core = atoi(cb->f[1]);
1642                         procwired(p, core);
1643                         shedule();
1644                         break;
1645                 case CMtrace:
1646                         switch (cb->nf) {
1647                                 case 1:
1648                                         p->trace ^= 1;
1649                                         break;
1650                                 case 2:
1651                                         p->trace = (atoi(cb->f[1]) != 0);
1652                                         break;
1653                                 default:
1654                                         error("args");
1655                         }
1656                         break;
1657                         /* real time */
1658                 case CMperiod:
1659                         if (p->edf == NULL)
1660                                 edfinit(p);
1661                         if (e = parsetime(&time, cb->f[1]))     /* time in ns */
1662                                 error(e);
1663                         edfstop(p);
1664                         p->edf->T = time / 1000;        /* Edf times are in µs */
1665                         break;
1666                 case CMdeadline:
1667                         if (p->edf == NULL)
1668                                 edfinit(p);
1669                         if (e = parsetime(&time, cb->f[1]))
1670                                 error(e);
1671                         edfstop(p);
1672                         p->edf->D = time / 1000;
1673                         break;
1674                 case CMcost:
1675                         if (p->edf == NULL)
1676                                 edfinit(p);
1677                         if (e = parsetime(&time, cb->f[1]))
1678                                 error(e);
1679                         edfstop(p);
1680                         p->edf->C = time / 1000;
1681                         break;
1682                 case CMsporadic:
1683                         if (p->edf == NULL)
1684                                 edfinit(p);
1685                         p->edf->flags |= Sporadic;
1686                         break;
1687                 case CMdeadlinenotes:
1688                         if (p->edf == NULL)
1689                                 edfinit(p);
1690                         p->edf->flags |= Sendnotes;
1691                         break;
1692                 case CMadmit:
1693                         if (p->edf == 0)
1694                                 error("edf params");
1695                         if (e = edfadmit(p))
1696                                 error(e);
1697                         break;
1698                 case CMextra:
1699                         if (p->edf == NULL)
1700                                 edfinit(p);
1701                         p->edf->flags |= Extratime;
1702                         break;
1703                 case CMexpel:
1704                         if (p->edf)
1705                                 edfstop(p);
1706                         break;
1707                 case CMevent:
1708                         if (current->trace)
1709                                 proctrace(up, SUser, 0);
1710                         break;
1711                 case CMcore:
1712                         core = atoi(cb->f[1]);
1713                         if (core >= MACHMAX)
1714                                 error("wrong core number");
1715                         else if (core == 0) {
1716                                 if (p->ac == NULL)
1717                                         error("not running in an ac");
1718                                 p->procctl = struct proc_totc;
1719                                 if (p != up && p->state == Exotic) {
1720                                         /* see the comment in postnote */
1721                                         intrac(p);
1722                                 }
1723                         } else {
1724                                 if (p->ac != NULL)
1725                                         error("running in an ac");
1726                                 if (core < 0)
1727                                         p->ac = getac(p, -1);
1728                                 else
1729                                         p->ac = getac(p, core);
1730                                 p->procctl = struct proc_toac;
1731                                 p->prepagemem = 1;
1732                         }
1733                         break;
1734         }
1735         poperror();
1736         kfree(cb);
1737 }
1738
1739 static int procstopped(void *a)
1740 {
1741         struct proc *p = a;
1742         return p->state == Stopped;
1743 }
1744
1745 static int
1746 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1747 {
1748         KMap *k;
1749         Pte *pte;
1750         Page *pg;
1751         Segment *s;
1752         uintptr_t soff, l;                      /* hmmmm */
1753         uint8_t *b;
1754         uintmem pgsz;
1755
1756         for (;;) {
1757                 s = seg(p, offset, 1);
1758                 if (s == 0)
1759                         error(Ebadarg);
1760
1761                 if (offset + n >= s->top)
1762                         n = s->top - offset;
1763
1764                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1765                         s = txt2data(p, s);
1766
1767                 s->steal++;
1768                 soff = offset - s->base;
1769                 if (waserror()) {
1770                         s->steal--;
1771                         nexterror();
1772                 }
1773                 if (fixfault(s, offset, read, 0, s->color) == 0)
1774                         break;
1775                 poperror();
1776                 s->steal--;
1777         }
1778         poperror();
1779         pte = s->map[soff / PTEMAPMEM];
1780         if (pte == 0)
1781                 panic("procctlmemio");
1782         pgsz = m->pgsz[s->pgszi];
1783         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1784         if (pagedout(pg))
1785                 panic("procctlmemio1");
1786
1787         l = pgsz - (offset & (pgsz - 1));
1788         if (n > l)
1789                 n = l;
1790
1791         k = kmap(pg);
1792         if (waserror()) {
1793                 s->steal--;
1794                 kunmap(k);
1795                 nexterror();
1796         }
1797         b = (uint8_t *) VA(k);
1798         b += offset & (pgsz - 1);
1799         if (read == 1)
1800                 memmove(va, b, n);      /* This can fault */
1801         else
1802                 memmove(b, va, n);
1803         poperror();
1804         kunmap(k);
1805
1806         /* Ensure the process sees text page changes */
1807         if (s->flushme)
1808                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1809
1810         s->steal--;
1811
1812         if (read == 0)
1813                 p->newtlb = 1;
1814
1815         return n;
1816 }
1817
1818 static Segment *txt2data(struct proc *p, Segment * s)
1819 {
1820         int i;
1821         Segment *ps;
1822
1823         ps = newseg(SG_DATA, s->base, s->size);
1824         ps->image = s->image;
1825         kref_get(&ps->image->ref, 1);
1826         ps->fstart = s->fstart;
1827         ps->flen = s->flen;
1828         ps->flushme = 1;
1829
1830         qlock(&p->seglock);
1831         for (i = 0; i < NSEG; i++)
1832                 if (p->seg[i] == s)
1833                         break;
1834         if (i == NSEG)
1835                 panic("segment gone");
1836
1837         qunlock(&s->lk);
1838         putseg(s);
1839         qlock(&ps->lk);
1840         p->seg[i] = ps;
1841         qunlock(&p->seglock);
1842
1843         return ps;
1844 }
1845
1846 Segment *data2txt(Segment * s)
1847 {
1848         Segment *ps;
1849
1850         ps = newseg(SG_TEXT, s->base, s->size);
1851         ps->image = s->image;
1852         kref_get(&ps->image->ref, 1);
1853         ps->fstart = s->fstart;
1854         ps->flen = s->flen;
1855         ps->flushme = 1;
1856
1857         return ps;
1858 }
1859 #endif