Get status entry in /proc
[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 Qwait:
526                 case Qregs:
527                 case Qfpregs:
528                 case Qkregs:
529                 case Qsyscall:
530                 case Qcore:
531                         nonone(p);
532                         break;
533
534                 case Qns:
535                         if (omode != OREAD)
536                                 error(Eperm);
537                         c->aux = kzmalloc(sizeof(struct mntwalk), KMALLOC_WAIT);
538                         break;
539         case Qstatus:
540                 break;
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 Qstatus:{
1147                         char buf[8 + 1 + 10 + 1 + 6 + 2]; /* 2 is paranoia */
1148                         snprintf(buf, sizeof(buf),
1149                                  "%8d %-10s %6d", p->pid, procstate2str(p->state), p->ppid);
1150                         kref_put(&p->p_kref);
1151                         return readstr(off, va, n, buf);
1152                 }
1153
1154                 case Qns:
1155                         //qlock(&p->debug);
1156                         if (waserror()) {
1157                                 //qunlock(&p->debug);
1158                                 kref_put(&p->p_kref);
1159                                 nexterror();
1160                         }
1161                         if (p->pgrp == NULL || p->pid != PID(c->qid))
1162                                 error(Eprocdied);
1163                         mw = c->aux;
1164                         if (mw->cddone) {
1165                                 poperror();
1166                                 //qunlock(&p->debug);
1167                                 kref_put(&p->p_kref);
1168                                 return 0;
1169                         }
1170                         mntscan(mw, p);
1171                         if (mw->mh == 0) {
1172                                 mw->cddone = 1;
1173                                 i = snprintf(va, n, "cd %s\n", p->dot->name->s);
1174                                 poperror();
1175                                 //qunlock(&p->debug);
1176                                 kref_put(&p->p_kref);
1177                                 return i;
1178                         }
1179                         int2flag(mw->cm->mflag, flag);
1180                         if (strcmp(mw->cm->to->name->s, "#M") == 0) {
1181                                 srv = srvname(mw->cm->to->mchan);
1182                                 i = snprintf(va, n, "mount %s %s %s %s\n", flag,
1183                                                         srv == NULL ? mw->cm->to->mchan->name->s : srv,
1184                                                         mw->mh->from->name->s,
1185                                                         mw->cm->spec ? mw->cm->spec : "");
1186                                 kfree(srv);
1187                         } else
1188                                 i = snprintf(va, n, "bind %s %s %s\n", flag,
1189                                                         mw->cm->to->name->s, mw->mh->from->name->s);
1190                         poperror();
1191                         //qunlock(&p->debug);
1192                         kref_put(&p->p_kref);
1193                         return i;
1194 #if 0
1195                 case Qnoteid:
1196                         r = readnum(offset, va, n, p->noteid, NUMSIZE);
1197                         kref_put(&p->p_kref);
1198                         return r;
1199                 case Qfd:
1200                         r = procfds(p, va, n, offset);
1201                         kref_put(&p->p_kref);
1202                         return r;
1203 #endif
1204         }
1205
1206         error(Egreg);
1207         return 0;       /* not reached */
1208 }
1209
1210 static void mntscan(struct mntwalk * mw, struct proc *p)
1211 {
1212         struct pgrp *pg;
1213         struct mount *t;
1214         struct mhead *f;
1215         int best, i, last, nxt;
1216
1217         pg = p->pgrp;
1218         rlock(&pg->ns);
1219
1220         nxt = 0;
1221         best = (int)(~0U >> 1); /* largest 2's complement int */
1222
1223         last = 0;
1224         if (mw->mh)
1225                 last = mw->cm->mountid;
1226
1227         for (i = 0; i < MNTHASH; i++) {
1228                 for (f = pg->mnthash[i]; f; f = f->hash) {
1229                         for (t = f->mount; t; t = t->next) {
1230                                 if (mw->mh == 0 || (t->mountid > last && t->mountid < best)) {
1231                                         mw->cm = t;
1232                                         mw->mh = f;
1233                                         best = mw->cm->mountid;
1234                                         nxt = 1;
1235                                 }
1236                         }
1237                 }
1238         }
1239         if (nxt == 0)
1240                 mw->mh = 0;
1241
1242         runlock(&pg->ns);
1243 }
1244
1245 static long
1246 procwrite(struct chan *c, void *va, long n, int64_t off)
1247 {
1248         ERRSTACK(2);
1249         error("procwrite: not yet");
1250         return 0;
1251 #if 0
1252         struct proc *p, *t;
1253         int i, id, l;
1254         char *args, buf[ERRMAX];
1255         uintptr_t offset;
1256
1257         if (c->qid.type & QTDIR)
1258                 error(Eisdir);
1259
1260         /* Use the remembered noteid in the channel rather
1261          * than the process pgrpid
1262          */
1263         if (QID(c->qid) == Qnotepg) {
1264                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1265                 return n;
1266         }
1267
1268         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1269                 error(Eprocdied);
1270
1271         qlock(&p->debug);
1272         if (waserror()) {
1273                 qunlock(&p->debug);
1274                 kref_put(&p->p_kref);
1275                 nexterror();
1276         }
1277         if (p->pid != PID(c->qid))
1278                 error(Eprocdied);
1279
1280         offset = off;
1281
1282         switch (QID(c->qid)) {
1283                 case Qargs:
1284                         if (n == 0)
1285                                 error(Eshort);
1286                         if (n >= sizeof buf - strlen(p->text) - 1)
1287                                 error(Etoobig);
1288                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1289                         args = kzmalloc(l + 1, KMALLOC_WAIT);
1290                         if (args == NULL)
1291                                 error(Enomem);
1292                         memmove(args, buf, l);
1293                         args[l] = 0;
1294                         kfree(p->args);
1295                         p->nargs = l;
1296                         p->args = args;
1297                         p->setargs = 1;
1298                         break;
1299
1300                 case Qmem:
1301                         if (p->state != Stopped)
1302                                 error(Ebadctl);
1303
1304                         n = procctlmemio(p, offset, n, va, 0);
1305                         break;
1306
1307                 case Qregs:
1308                         if (offset >= sizeof(Ureg))
1309                                 n = 0;
1310                         else if (offset + n > sizeof(Ureg))
1311                                 n = sizeof(Ureg) - offset;
1312                         if (p->dbgreg == 0)
1313                                 error(Enoreg);
1314                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1315                         break;
1316
1317                 case Qfpregs:
1318                         n = fpudevprocio(p, va, n, offset, 1);
1319                         break;
1320
1321                 case Qctl:
1322                         procctlreq(p, va, n);
1323                         break;
1324
1325                 case Qnote:
1326                         if (p->kp)
1327                                 error(Eperm);
1328                         if (n >= ERRMAX - 1)
1329                                 error(Etoobig);
1330                         memmove(buf, va, n);
1331                         buf[n] = 0;
1332                         if (!postnote(p, 0, buf, NUser))
1333                                 error("note not posted");
1334                         break;
1335                 case Qnoteid:
1336                         id = atoi(va);
1337                         if (id == p->pid) {
1338                                 p->noteid = id;
1339                                 break;
1340                         }
1341                         /* Careful here, check that you know what the iterator is doing */
1342                         for (i = 0; (t = pid_nth(i)) != NULL; i++) {
1343                                 if (t->state == Dead || t->noteid != id) {
1344                                         kref_put(&p->p_kref);
1345                                         continue;
1346                                 }
1347                                 if (strcmp(p->user, t->user) != 0) {
1348                                         kref_put(&p->p_kref);
1349                                         error(Eperm);
1350                                 }
1351                                 kref_put(&p->p_kref);
1352                                 p->noteid = id;
1353                                 break;
1354                         }
1355                         if (p->noteid != id)
1356                                 error(Ebadarg);
1357                         break;
1358                 default:
1359                         poperror();
1360                         qunlock(&p->debug);
1361                         kref_put(&p->p_kref);
1362                         pprint("unknown qid %#llux in procwrite\n", c->qid.path);
1363                         error(Egreg);
1364         }
1365         poperror();
1366         qunlock(&p->debug);
1367         kref_put(&p->p_kref);
1368         return n;
1369 #endif
1370 }
1371
1372 struct dev procdevtab __devtab = {
1373         'p',
1374         "proc",
1375
1376         devreset,
1377         procinit,
1378         devshutdown,
1379         procattach,
1380         procwalk,
1381         procstat,
1382         procopen,
1383         devcreate,
1384         procclose,
1385         procread,
1386         devbread,
1387         procwrite,
1388         devbwrite,
1389         devremove,
1390         procwstat,
1391         devpower,
1392         devchaninfo,
1393 };
1394
1395 #if 0
1396 static struct chan *proctext(struct chan *c, struct proc *p)
1397 {
1398         ERRSTACK(2);
1399         struct chan *tc;
1400         Image *i;
1401         Segment *s;
1402
1403         s = p->seg[TSEG];
1404         if (s == 0)
1405                 error(Enonexist);
1406         if (p->state == Dead)
1407                 error(Eprocdied);
1408
1409         lock(s);
1410         i = s->image;
1411         if (i == 0) {
1412                 unlock(s);
1413                 error(Eprocdied);
1414         }
1415         unlock(s);
1416
1417         lock(i);
1418         if (waserror()) {
1419                 unlock(i);
1420                 nexterror();
1421         }
1422
1423         tc = i->c;
1424         if (tc == 0)
1425                 error(Eprocdied);
1426
1427         /* TODO: what do you want here?  you can't get a kref and have the new val
1428          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1429         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1430                 || tc->mode != OREAD) {
1431                 cclose(tc);
1432                 error(Eprocdied);
1433         }
1434
1435         if (p->pid != PID(c->qid)) {
1436                 cclose(tc);
1437                 error(Eprocdied);
1438         }
1439
1440         poperror();
1441         unlock(i);
1442
1443         return tc;
1444 }
1445
1446 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1447  * among other things, and we'll need to rewrite this for akaros */
1448 void procstopwait(struct proc *p, int ctl)
1449 {
1450         ERRSTACK(2);
1451         int pid;
1452
1453         if (p->pdbg)
1454                 error(Einuse);
1455         if (procstopped(p) || p->state == Broken)
1456                 return;
1457
1458         if (ctl != 0)
1459                 p->procctl = ctl;
1460         p->pdbg = up;
1461         pid = p->pid;
1462         qunlock(&p->debug);
1463         current->psstate = "Stopwait";
1464         if (waserror()) {
1465                 p->pdbg = 0;
1466                 qlock(&p->debug);
1467                 nexterror();
1468         }
1469         rendez_sleep(&current->sleep, procstopped, p);
1470         poperror();
1471         qlock(&p->debug);
1472         if (p->pid != pid)
1473                 error(Eprocdied);
1474 }
1475
1476 static void procctlcloseone(struct proc *p, struct fgrp *f, int fd)
1477 {
1478         struct chan *c;
1479
1480         c = f->fd[fd];
1481         if (c == NULL)
1482                 return;
1483         f->fd[fd] = NULL;
1484         unlock(f);
1485         qunlock(&p->debug);
1486         cclose(c);
1487         qlock(&p->debug);
1488         lock(f);
1489 }
1490
1491 void procctlclosefiles(struct proc *p, int all, int fd)
1492 {
1493         int i;
1494         struct fgrp *f;
1495
1496         f = p->fgrp;
1497         if (f == NULL)
1498                 error(Eprocdied);
1499
1500         lock(f);
1501         f->ref++;
1502         if (all)
1503                 for (i = 0; i < f->maxfd; i++)
1504                         procctlcloseone(p, f, i);
1505         else
1506                 procctlcloseone(p, f, fd);
1507         unlock(f);
1508         closefgrp(f);
1509 }
1510
1511 static char *parsetime(int64_t * rt, char *s)
1512 {
1513         uint64_t ticks;
1514         uint32_t l;
1515         char *e, *p;
1516         static int p10[] =
1517                 { 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };
1518
1519         if (s == NULL)
1520                 return ("missing value");
1521         ticks = strtoul(s, &e, 10);
1522         if (*e == '.') {
1523                 p = e + 1;
1524                 l = strtoul(p, &e, 10);
1525                 if (e - p > nelem(p10))
1526                         return "too many digits after decimal point";
1527                 if (e - p == 0)
1528                         return "ill-formed number";
1529                 l *= p10[e - p - 1];
1530         } else
1531                 l = 0;
1532         if (*e == '\0' || strcmp(e, "s") == 0) {
1533                 ticks = 1000000000 * ticks + l;
1534         } else if (strcmp(e, "ms") == 0) {
1535                 ticks = 1000000 * ticks + l / 1000;
1536         } else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0) {
1537                 ticks = 1000 * ticks + l / 1000000;
1538         } else if (strcmp(e, "ns") != 0)
1539                 return "unrecognized unit";
1540         *rt = ticks;
1541         return NULL;
1542 }
1543
1544 static void procctlreq(struct proc *p, char *va, int n)
1545 {
1546         ERRSTACK(2);
1547         Segment *s;
1548         int npc, pri, core;
1549         struct cmdbuf *cb;
1550         struct cmdtab *ct;
1551         int64_t time;
1552         char *e;
1553
1554         if (p->kp)      /* no ctl requests to kprocs */
1555                 error(Eperm);
1556
1557         cb = parsecmd(va, n);
1558         if (waserror()) {
1559                 kfree(cb);
1560                 nexterror();
1561         }
1562
1563         ct = lookupcmd(cb, proccmd, nelem(proccmd));
1564
1565         switch (ct->index) {
1566                 case CMclose:
1567                         procctlclosefiles(p, 0, atoi(cb->f[1]));
1568                         break;
1569                 case CMclosefiles:
1570                         procctlclosefiles(p, 1, 0);
1571                         break;
1572                 case CMhang:
1573                         p->hang = 1;
1574                         break;
1575                 case CMkill:
1576                         switch (p->state) {
1577                                 case Broken:
1578                                         unbreak(p);
1579                                         break;
1580                                 case Stopped:
1581                                 case Semdown:
1582                                         p->procctl = struct proc_exitme;
1583                                         postnote(p, 0, "sys: killed", NExit);
1584                                         ready(p);
1585                                         break;
1586                                 default:
1587                                         p->procctl = struct proc_exitme;
1588                                         postnote(p, 0, "sys: killed", NExit);
1589                         }
1590                         break;
1591                 case CMnohang:
1592                         p->hang = 0;
1593                         break;
1594                 case CMnoswap:
1595                         p->noswap = 1;
1596                         break;
1597                 case CMpri:
1598                         pri = atoi(cb->f[1]);
1599                         if (pri > PriNormal && !iseve())
1600                                 error(Eperm);
1601                         procpriority(p, pri, 0);
1602                         break;
1603                 case CMfixedpri:
1604                         pri = atoi(cb->f[1]);
1605                         if (pri > PriNormal && !iseve())
1606                                 error(Eperm);
1607                         procpriority(p, pri, 1);
1608                         break;
1609                 case CMprivate:
1610                         p->privatemem = 1;
1611                         break;
1612                 case CMprofile:
1613                         s = p->seg[TSEG];
1614                         if (s == 0 || (s->type & SG_TYPE) != SG_TEXT)
1615                                 error(Ebadctl);
1616                         if (s->profile != 0)
1617                                 kfree(s->profile);
1618                         npc = (s->top - s->base) >> LRESPROF;
1619                         s->profile = kzmalloc(npc * sizeof(*s->profile), KMALLOC_WAIT);
1620                         if (s->profile == 0)
1621                                 error(Enomem);
1622                         break;
1623                 case CMstart:
1624                         if (p->state != Stopped)
1625                                 error(Ebadctl);
1626                         ready(p);
1627                         break;
1628                 case CMstartstop:
1629                         if (p->state != Stopped)
1630                                 error(Ebadctl);
1631                         p->procctl = struct proc_traceme;
1632                         ready(p);
1633                         procstopwait(p, struct proc_traceme);
1634                         break;
1635                 case CMstartsyscall:
1636                         if (p->state != Stopped)
1637                                 error(Ebadctl);
1638                         p->procctl = struct proc_tracesyscall;
1639                         ready(p);
1640                         procstopwait(p, struct proc_tracesyscall);
1641                         break;
1642                 case CMstop:
1643                         procstopwait(p, struct proc_stopme);
1644                         break;
1645                 case CMwaitstop:
1646                         procstopwait(p, 0);
1647                         break;
1648                 case CMwired:
1649                         core = atoi(cb->f[1]);
1650                         procwired(p, core);
1651                         shedule();
1652                         break;
1653                 case CMtrace:
1654                         switch (cb->nf) {
1655                                 case 1:
1656                                         p->trace ^= 1;
1657                                         break;
1658                                 case 2:
1659                                         p->trace = (atoi(cb->f[1]) != 0);
1660                                         break;
1661                                 default:
1662                                         error("args");
1663                         }
1664                         break;
1665                         /* real time */
1666                 case CMperiod:
1667                         if (p->edf == NULL)
1668                                 edfinit(p);
1669                         if (e = parsetime(&time, cb->f[1]))     /* time in ns */
1670                                 error(e);
1671                         edfstop(p);
1672                         p->edf->T = time / 1000;        /* Edf times are in µs */
1673                         break;
1674                 case CMdeadline:
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->D = time / 1000;
1681                         break;
1682                 case CMcost:
1683                         if (p->edf == NULL)
1684                                 edfinit(p);
1685                         if (e = parsetime(&time, cb->f[1]))
1686                                 error(e);
1687                         edfstop(p);
1688                         p->edf->C = time / 1000;
1689                         break;
1690                 case CMsporadic:
1691                         if (p->edf == NULL)
1692                                 edfinit(p);
1693                         p->edf->flags |= Sporadic;
1694                         break;
1695                 case CMdeadlinenotes:
1696                         if (p->edf == NULL)
1697                                 edfinit(p);
1698                         p->edf->flags |= Sendnotes;
1699                         break;
1700                 case CMadmit:
1701                         if (p->edf == 0)
1702                                 error("edf params");
1703                         if (e = edfadmit(p))
1704                                 error(e);
1705                         break;
1706                 case CMextra:
1707                         if (p->edf == NULL)
1708                                 edfinit(p);
1709                         p->edf->flags |= Extratime;
1710                         break;
1711                 case CMexpel:
1712                         if (p->edf)
1713                                 edfstop(p);
1714                         break;
1715                 case CMevent:
1716                         if (current->trace)
1717                                 proctrace(up, SUser, 0);
1718                         break;
1719                 case CMcore:
1720                         core = atoi(cb->f[1]);
1721                         if (core >= MACHMAX)
1722                                 error("wrong core number");
1723                         else if (core == 0) {
1724                                 if (p->ac == NULL)
1725                                         error("not running in an ac");
1726                                 p->procctl = struct proc_totc;
1727                                 if (p != up && p->state == Exotic) {
1728                                         /* see the comment in postnote */
1729                                         intrac(p);
1730                                 }
1731                         } else {
1732                                 if (p->ac != NULL)
1733                                         error("running in an ac");
1734                                 if (core < 0)
1735                                         p->ac = getac(p, -1);
1736                                 else
1737                                         p->ac = getac(p, core);
1738                                 p->procctl = struct proc_toac;
1739                                 p->prepagemem = 1;
1740                         }
1741                         break;
1742         }
1743         poperror();
1744         kfree(cb);
1745 }
1746
1747 static int procstopped(void *a)
1748 {
1749         struct proc *p = a;
1750         return p->state == Stopped;
1751 }
1752
1753 static int
1754 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1755 {
1756         KMap *k;
1757         Pte *pte;
1758         Page *pg;
1759         Segment *s;
1760         uintptr_t soff, l;                      /* hmmmm */
1761         uint8_t *b;
1762         uintmem pgsz;
1763
1764         for (;;) {
1765                 s = seg(p, offset, 1);
1766                 if (s == 0)
1767                         error(Ebadarg);
1768
1769                 if (offset + n >= s->top)
1770                         n = s->top - offset;
1771
1772                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1773                         s = txt2data(p, s);
1774
1775                 s->steal++;
1776                 soff = offset - s->base;
1777                 if (waserror()) {
1778                         s->steal--;
1779                         nexterror();
1780                 }
1781                 if (fixfault(s, offset, read, 0, s->color) == 0)
1782                         break;
1783                 poperror();
1784                 s->steal--;
1785         }
1786         poperror();
1787         pte = s->map[soff / PTEMAPMEM];
1788         if (pte == 0)
1789                 panic("procctlmemio");
1790         pgsz = m->pgsz[s->pgszi];
1791         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1792         if (pagedout(pg))
1793                 panic("procctlmemio1");
1794
1795         l = pgsz - (offset & (pgsz - 1));
1796         if (n > l)
1797                 n = l;
1798
1799         k = kmap(pg);
1800         if (waserror()) {
1801                 s->steal--;
1802                 kunmap(k);
1803                 nexterror();
1804         }
1805         b = (uint8_t *) VA(k);
1806         b += offset & (pgsz - 1);
1807         if (read == 1)
1808                 memmove(va, b, n);      /* This can fault */
1809         else
1810                 memmove(b, va, n);
1811         poperror();
1812         kunmap(k);
1813
1814         /* Ensure the process sees text page changes */
1815         if (s->flushme)
1816                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1817
1818         s->steal--;
1819
1820         if (read == 0)
1821                 p->newtlb = 1;
1822
1823         return n;
1824 }
1825
1826 static Segment *txt2data(struct proc *p, Segment * s)
1827 {
1828         int i;
1829         Segment *ps;
1830
1831         ps = newseg(SG_DATA, s->base, s->size);
1832         ps->image = s->image;
1833         kref_get(&ps->image->ref, 1);
1834         ps->fstart = s->fstart;
1835         ps->flen = s->flen;
1836         ps->flushme = 1;
1837
1838         qlock(&p->seglock);
1839         for (i = 0; i < NSEG; i++)
1840                 if (p->seg[i] == s)
1841                         break;
1842         if (i == NSEG)
1843                 panic("segment gone");
1844
1845         qunlock(&s->lk);
1846         putseg(s);
1847         qlock(&ps->lk);
1848         p->seg[i] = ps;
1849         qunlock(&p->seglock);
1850
1851         return ps;
1852 }
1853
1854 Segment *data2txt(Segment * s)
1855 {
1856         Segment *ps;
1857
1858         ps = newseg(SG_TEXT, s->base, s->size);
1859         ps->image = s->image;
1860         kref_get(&ps->image->ref, 1);
1861         ps->fstart = s->fstart;
1862         ps->flen = s->flen;
1863         ps->flushme = 1;
1864
1865         return ps;
1866 }
1867 #endif