FreeBSD/Linux Kernel Cross Reference
sys/port/devproc.c
1 #include "u.h"
2 #include <trace.h>
3 #include "tos.h"
4 #include "../port/lib.h"
5 #include "mem.h"
6 #include "dat.h"
7 #include "fns.h"
8 #include "../port/error.h"
9 #include "ureg.h"
10 #include "edf.h"
11
12 enum
13 {
14 Qdir,
15 Qtrace,
16 Qargs,
17 Qctl,
18 Qfd,
19 Qfpregs,
20 Qkregs,
21 Qmem,
22 Qnote,
23 Qnoteid,
24 Qnotepg,
25 Qns,
26 Qproc,
27 Qregs,
28 Qsegment,
29 Qstatus,
30 Qtext,
31 Qwait,
32 Qprofile,
33 };
34
35 enum
36 {
37 CMclose,
38 CMclosefiles,
39 CMfixedpri,
40 CMhang,
41 CMkill,
42 CMnohang,
43 CMnoswap,
44 CMpri,
45 CMprivate,
46 CMprofile,
47 CMstart,
48 CMstartstop,
49 CMstartsyscall,
50 CMstop,
51 CMwaitstop,
52 CMwired,
53 CMtrace,
54 /* real time */
55 CMperiod,
56 CMdeadline,
57 CMcost,
58 CMsporadic,
59 CMdeadlinenotes,
60 CMadmit,
61 CMextra,
62 CMexpel,
63 CMevent,
64 };
65
66 enum{
67 Nevents = 0x4000,
68 Emask = Nevents - 1,
69 };
70
71 #define STATSIZE (2*KNAMELEN+12+9*12)
72 /*
73 * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
74 * particularly on shared servers.
75 * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
76 */
77 Dirtab procdir[] =
78 {
79 "args", {Qargs}, 0, 0660,
80 "ctl", {Qctl}, 0, 0000,
81 "fd", {Qfd}, 0, 0444,
82 "fpregs", {Qfpregs}, sizeof(FPsave), 0000,
83 "kregs", {Qkregs}, sizeof(Ureg), 0400,
84 "mem", {Qmem}, 0, 0000,
85 "note", {Qnote}, 0, 0000,
86 "noteid", {Qnoteid}, 0, 0664,
87 "notepg", {Qnotepg}, 0, 0000,
88 "ns", {Qns}, 0, 0444,
89 "proc", {Qproc}, 0, 0400,
90 "regs", {Qregs}, sizeof(Ureg), 0000,
91 "segment", {Qsegment}, 0, 0444,
92 "status", {Qstatus}, STATSIZE, 0444,
93 "text", {Qtext}, 0, 0000,
94 "wait", {Qwait}, 0, 0400,
95 "profile", {Qprofile}, 0, 0400,
96 };
97
98 static
99 Cmdtab proccmd[] = {
100 CMclose, "close", 2,
101 CMclosefiles, "closefiles", 1,
102 CMfixedpri, "fixedpri", 2,
103 CMhang, "hang", 1,
104 CMnohang, "nohang", 1,
105 CMnoswap, "noswap", 1,
106 CMkill, "kill", 1,
107 CMpri, "pri", 2,
108 CMprivate, "private", 1,
109 CMprofile, "profile", 1,
110 CMstart, "start", 1,
111 CMstartstop, "startstop", 1,
112 CMstartsyscall, "startsyscall", 1,
113 CMstop, "stop", 1,
114 CMwaitstop, "waitstop", 1,
115 CMwired, "wired", 2,
116 CMtrace, "trace", 0,
117 CMperiod, "period", 2,
118 CMdeadline, "deadline", 2,
119 CMcost, "cost", 2,
120 CMsporadic, "sporadic", 1,
121 CMdeadlinenotes, "deadlinenotes", 1,
122 CMadmit, "admit", 1,
123 CMextra, "extra", 1,
124 CMexpel, "expel", 1,
125 CMevent, "event", 1,
126 };
127
128 /* Segment type from portdat.h */
129 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
130
131 /*
132 * Qids are, in path:
133 * 4 bits of file type (qids above)
134 * 23 bits of process slot number + 1
135 * in vers,
136 * 32 bits of pid, for consistency checking
137 * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
138 */
139 #define QSHIFT 5 /* location in qid of proc slot # */
140
141 #define QID(q) ((((ulong)(q).path)&0x0000001F)>>0)
142 #define SLOT(q) (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
143 #define PID(q) ((q).vers)
144 #define NOTEID(q) ((q).vers)
145
146 void procctlreq(Proc*, char*, int);
147 int procctlmemio(Proc*, ulong, int, void*, int);
148 Chan* proctext(Chan*, Proc*);
149 Segment* txt2data(Proc*, Segment*);
150 int procstopped(void*);
151 void mntscan(Mntwalk*, Proc*);
152
153 static Traceevent *tevents;
154 static Lock tlock;
155 static int topens;
156 static int tproduced, tconsumed;
157 void (*proctrace)(Proc*, int, vlong);
158
159 extern int unfair;
160
161 static void
162 profclock(Ureg *ur, Timer *)
163 {
164 Tos *tos;
165
166 if(up == 0 || up->state != Running)
167 return;
168
169 /* user profiling clock */
170 if(userureg(ur)){
171 tos = (Tos*)(USTKTOP-sizeof(Tos));
172 tos->clock += TK2MS(1);
173 segclock(ur->pc);
174 }
175 }
176
177 static int
178 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
179 {
180 Qid qid;
181 Proc *p;
182 char *ename;
183 Segment *q;
184 ulong pid, path, perm, len;
185
186 if(s == DEVDOTDOT){
187 mkqid(&qid, Qdir, 0, QTDIR);
188 devdir(c, qid, "#p", 0, eve, 0555, dp);
189 return 1;
190 }
191
192 if(c->qid.path == Qdir){
193 if(s == 0){
194 strcpy(up->genbuf, "trace");
195 mkqid(&qid, Qtrace, -1, QTFILE);
196 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
197 return 1;
198 }
199
200 if(name != nil){
201 /* ignore s and use name to find pid */
202 pid = strtol(name, &ename, 10);
203 if(pid==0 || ename[0]!='\0')
204 return -1;
205 s = procindex(pid);
206 if(s < 0)
207 return -1;
208 }
209 else if(--s >= conf.nproc)
210 return -1;
211
212 p = proctab(s);
213 pid = p->pid;
214 if(pid == 0)
215 return 0;
216 sprint(up->genbuf, "%lud", pid);
217 /*
218 * String comparison is done in devwalk so name must match its formatted pid
219 */
220 if(name != nil && strcmp(name, up->genbuf) != 0)
221 return -1;
222 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
223 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
224 return 1;
225 }
226 if(c->qid.path == Qtrace){
227 strcpy(up->genbuf, "trace");
228 mkqid(&qid, Qtrace, -1, QTFILE);
229 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
230 return 1;
231 }
232 if(s >= nelem(procdir))
233 return -1;
234 if(tab)
235 panic("procgen");
236
237 tab = &procdir[s];
238 path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */
239
240 p = proctab(SLOT(c->qid));
241 perm = tab->perm;
242 if(perm == 0)
243 perm = p->procmode;
244 else /* just copy read bits */
245 perm |= p->procmode & 0444;
246
247 len = tab->length;
248 switch(QID(c->qid)) {
249 case Qwait:
250 len = p->nwait; /* incorrect size, but >0 means there's something to read */
251 break;
252 case Qprofile:
253 q = p->seg[TSEG];
254 if(q && q->profile) {
255 len = (q->top-q->base)>>LRESPROF;
256 len *= sizeof(*q->profile);
257 }
258 break;
259 }
260
261 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
262 devdir(c, qid, tab->name, len, p->user, perm, dp);
263 return 1;
264 }
265
266 static void
267 _proctrace(Proc* p, Tevent etype, vlong ts)
268 {
269 Traceevent *te;
270
271 if (p->trace == 0 || topens == 0 ||
272 tproduced - tconsumed >= Nevents)
273 return;
274
275 te = &tevents[tproduced&Emask];
276 te->pid = p->pid;
277 te->etype = etype;
278 if (ts == 0)
279 te->time = todget(nil);
280 else
281 te->time = ts;
282 tproduced++;
283 }
284
285 static void
286 procinit(void)
287 {
288 if(conf.nproc >= (1<<(16-QSHIFT))-1)
289 print("warning: too many procs for devproc\n");
290 addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */
291 }
292
293 static Chan*
294 procattach(char *spec)
295 {
296 return devattach('p', spec);
297 }
298
299 static Walkqid*
300 procwalk(Chan *c, Chan *nc, char **name, int nname)
301 {
302 return devwalk(c, nc, name, nname, 0, 0, procgen);
303 }
304
305 static int
306 procstat(Chan *c, uchar *db, int n)
307 {
308 return devstat(c, db, n, 0, 0, procgen);
309 }
310
311 /*
312 * none can't read or write state on other
313 * processes. This is to contain access of
314 * servers running as none should they be
315 * subverted by, for example, a stack attack.
316 */
317 static void
318 nonone(Proc *p)
319 {
320 if(p == up)
321 return;
322 if(strcmp(up->user, "none") != 0)
323 return;
324 if(iseve())
325 return;
326 error(Eperm);
327 }
328
329 static Chan*
330 procopen(Chan *c, int omode)
331 {
332 Proc *p;
333 Pgrp *pg;
334 Chan *tc;
335 int pid;
336
337 if(c->qid.type & QTDIR)
338 return devopen(c, omode, 0, 0, procgen);
339
340 if(QID(c->qid) == Qtrace){
341 if (omode != OREAD)
342 error(Eperm);
343 lock(&tlock);
344 if (waserror()){
345 unlock(&tlock);
346 nexterror();
347 }
348 if (topens > 0)
349 error("already open");
350 topens++;
351 if (tevents == nil){
352 tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
353 if(tevents == nil)
354 error(Enomem);
355 tproduced = tconsumed = 0;
356 }
357 proctrace = _proctrace;
358 unlock(&tlock);
359 poperror();
360
361 c->mode = openmode(omode);
362 c->flag |= COPEN;
363 c->offset = 0;
364 return c;
365 }
366
367 p = proctab(SLOT(c->qid));
368 qlock(&p->debug);
369 if(waserror()){
370 qunlock(&p->debug);
371 nexterror();
372 }
373 pid = PID(c->qid);
374 if(p->pid != pid)
375 error(Eprocdied);
376
377 omode = openmode(omode);
378
379 switch(QID(c->qid)){
380 case Qtext:
381 if(omode != OREAD)
382 error(Eperm);
383 tc = proctext(c, p);
384 tc->offset = 0;
385 qunlock(&p->debug);
386 poperror();
387 return tc;
388
389 case Qproc:
390 case Qkregs:
391 case Qsegment:
392 case Qprofile:
393 case Qfd:
394 if(omode != OREAD)
395 error(Eperm);
396 break;
397
398 case Qnote:
399 if(p->privatemem)
400 error(Eperm);
401 break;
402
403 case Qmem:
404 case Qctl:
405 if(p->privatemem)
406 error(Eperm);
407 nonone(p);
408 break;
409
410 case Qargs:
411 case Qnoteid:
412 case Qstatus:
413 case Qwait:
414 case Qregs:
415 case Qfpregs:
416 nonone(p);
417 break;
418
419 case Qns:
420 if(omode != OREAD)
421 error(Eperm);
422 c->aux = malloc(sizeof(Mntwalk));
423 break;
424
425 case Qnotepg:
426 nonone(p);
427 pg = p->pgrp;
428 if(pg == nil)
429 error(Eprocdied);
430 if(omode!=OWRITE || pg->pgrpid == 1)
431 error(Eperm);
432 c->pgrpid.path = pg->pgrpid+1;
433 c->pgrpid.vers = p->noteid;
434 break;
435
436 default:
437 pprint("procopen %lux\n", c->qid);
438 error(Egreg);
439 }
440
441 /* Affix pid to qid */
442 if(p->state != Dead)
443 c->qid.vers = p->pid;
444
445 /* make sure the process slot didn't get reallocated while we were playing */
446 coherence();
447 if(p->pid != pid)
448 error(Eprocdied);
449
450 tc = devopen(c, omode, 0, 0, procgen);
451 qunlock(&p->debug);
452 poperror();
453
454 return tc;
455 }
456
457 static int
458 procwstat(Chan *c, uchar *db, int n)
459 {
460 Proc *p;
461 Dir *d;
462
463 if(c->qid.type&QTDIR)
464 error(Eperm);
465
466 if(QID(c->qid) == Qtrace)
467 return devwstat(c, db, n);
468
469 p = proctab(SLOT(c->qid));
470 nonone(p);
471 d = nil;
472 if(waserror()){
473 free(d);
474 qunlock(&p->debug);
475 nexterror();
476 }
477 qlock(&p->debug);
478
479 if(p->pid != PID(c->qid))
480 error(Eprocdied);
481
482 if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
483 error(Eperm);
484
485 d = smalloc(sizeof(Dir)+n);
486 n = convM2D(db, n, &d[0], (char*)&d[1]);
487 if(n == 0)
488 error(Eshortstat);
489 if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
490 if(strcmp(up->user, eve) != 0)
491 error(Eperm);
492 else
493 kstrdup(&p->user, d->uid);
494 }
495 if(d->mode != ~0UL)
496 p->procmode = d->mode&0777;
497
498 poperror();
499 free(d);
500 qunlock(&p->debug);
501 return n;
502 }
503
504
505 static long
506 procoffset(long offset, char *va, int *np)
507 {
508 if(offset > 0) {
509 offset -= *np;
510 if(offset < 0) {
511 memmove(va, va+*np+offset, -offset);
512 *np = -offset;
513 }
514 else
515 *np = 0;
516 }
517 return offset;
518 }
519
520 static int
521 procqidwidth(Chan *c)
522 {
523 char buf[32];
524
525 return sprint(buf, "%lud", c->qid.vers);
526 }
527
528 int
529 procfdprint(Chan *c, int fd, int w, char *s, int ns)
530 {
531 int n;
532
533 if(w == 0)
534 w = procqidwidth(c);
535 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
536 fd,
537 &"r w rw"[(c->mode&3)<<1],
538 devtab[c->type]->dc, c->dev,
539 c->qid.path, w, c->qid.vers, c->qid.type,
540 c->iounit, c->offset, c->path->s);
541 return n;
542 }
543
544 static int
545 procfds(Proc *p, char *va, int count, long offset)
546 {
547 Fgrp *f;
548 Chan *c;
549 char buf[256];
550 int n, i, w, ww;
551 char *a;
552
553 /* print to buf to avoid holding fgrp lock while writing to user space */
554 if(count > sizeof buf)
555 count = sizeof buf;
556 a = buf;
557
558 qlock(&p->debug);
559 f = p->fgrp;
560 if(f == nil){
561 qunlock(&p->debug);
562 return 0;
563 }
564 lock(f);
565 if(waserror()){
566 unlock(f);
567 qunlock(&p->debug);
568 nexterror();
569 }
570
571 n = readstr(0, a, count, p->dot->path->s);
572 n += snprint(a+n, count-n, "\n");
573 offset = procoffset(offset, a, &n);
574 /* compute width of qid.path */
575 w = 0;
576 for(i = 0; i <= f->maxfd; i++) {
577 c = f->fd[i];
578 if(c == nil)
579 continue;
580 ww = procqidwidth(c);
581 if(ww > w)
582 w = ww;
583 }
584 for(i = 0; i <= f->maxfd; i++) {
585 c = f->fd[i];
586 if(c == nil)
587 continue;
588 n += procfdprint(c, i, w, a+n, count-n);
589 offset = procoffset(offset, a, &n);
590 }
591 unlock(f);
592 qunlock(&p->debug);
593 poperror();
594
595 /* copy result to user space, now that locks are released */
596 memmove(va, buf, n);
597
598 return n;
599 }
600
601 static void
602 procclose(Chan * c)
603 {
604 if(QID(c->qid) == Qtrace){
605 lock(&tlock);
606 if(topens > 0)
607 topens--;
608 if(topens == 0)
609 proctrace = nil;
610 unlock(&tlock);
611 }
612 if(QID(c->qid) == Qns && c->aux != 0)
613 free(c->aux);
614 }
615
616 static void
617 int2flag(int flag, char *s)
618 {
619 if(flag == 0){
620 *s = '\0';
621 return;
622 }
623 *s++ = '-';
624 if(flag & MAFTER)
625 *s++ = 'a';
626 if(flag & MBEFORE)
627 *s++ = 'b';
628 if(flag & MCREATE)
629 *s++ = 'c';
630 if(flag & MCACHE)
631 *s++ = 'C';
632 *s = '\0';
633 }
634
635 static int
636 procargs(Proc *p, char *buf, int nbuf)
637 {
638 int j, k, m;
639 char *a;
640 int n;
641
642 a = p->args;
643 if(p->setargs){
644 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
645 return strlen(buf);
646 }
647 n = p->nargs;
648 for(j = 0; j < nbuf - 1; j += m){
649 if(n <= 0)
650 break;
651 if(j != 0)
652 buf[j++] = ' ';
653 m = snprint(buf+j, nbuf-j, "%q", a);
654 k = strlen(a) + 1;
655 a += k;
656 n -= k;
657 }
658 return j;
659 }
660
661 static int
662 eventsavailable(void *)
663 {
664 return tproduced > tconsumed;
665 }
666
667 static long
668 procread(Chan *c, void *va, long n, vlong off)
669 {
670 /* NSEG*32 was too small for worst cases */
671 char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
672 int i, j, m, navail, ne, pid, rsize;
673 long l;
674 uchar *rptr;
675 ulong offset;
676 Confmem *cm;
677 Mntwalk *mw;
678 Proc *p;
679 Segment *sg, *s;
680 Ureg kur;
681 Waitq *wq;
682
683 a = va;
684 offset = off;
685
686 if(c->qid.type & QTDIR)
687 return devdirread(c, a, n, 0, 0, procgen);
688
689 if(QID(c->qid) == Qtrace){
690 if(!eventsavailable(nil))
691 return 0;
692
693 rptr = (uchar*)va;
694 navail = tproduced - tconsumed;
695 if(navail > n / sizeof(Traceevent))
696 navail = n / sizeof(Traceevent);
697 while(navail > 0) {
698 ne = ((tconsumed & Emask) + navail > Nevents)?
699 Nevents - (tconsumed & Emask): navail;
700 memmove(rptr, &tevents[tconsumed & Emask],
701 ne * sizeof(Traceevent));
702
703 tconsumed += ne;
704 rptr += ne * sizeof(Traceevent);
705 navail -= ne;
706 }
707 return rptr - (uchar*)va;
708 }
709
710 p = proctab(SLOT(c->qid));
711 if(p->pid != PID(c->qid))
712 error(Eprocdied);
713
714 switch(QID(c->qid)){
715 case Qargs:
716 qlock(&p->debug);
717 j = procargs(p, up->genbuf, sizeof up->genbuf);
718 qunlock(&p->debug);
719 if(offset >= j)
720 return 0;
721 if(offset+n > j)
722 n = j-offset;
723 memmove(a, &up->genbuf[offset], n);
724 return n;
725
726 case Qmem:
727 if(offset < KZERO)
728 return procctlmemio(p, offset, n, va, 1);
729
730 if(!iseve())
731 error(Eperm);
732
733 /* validate kernel addresses */
734 if(offset < (ulong)end) {
735 if(offset+n > (ulong)end)
736 n = (ulong)end - offset;
737 memmove(a, (char*)offset, n);
738 return n;
739 }
740 for(i=0; i<nelem(conf.mem); i++){
741 cm = &conf.mem[i];
742 /* klimit-1 because klimit might be zero! */
743 if(cm->kbase <= offset && offset <= cm->klimit-1){
744 if(offset+n >= cm->klimit-1)
745 n = cm->klimit - offset;
746 memmove(a, (char*)offset, n);
747 return n;
748 }
749 }
750 error(Ebadarg);
751
752 case Qprofile:
753 s = p->seg[TSEG];
754 if(s == 0 || s->profile == 0)
755 error("profile is off");
756 i = (s->top-s->base)>>LRESPROF;
757 i *= sizeof(*s->profile);
758 if(offset >= i)
759 return 0;
760 if(offset+n > i)
761 n = i - offset;
762 memmove(a, ((char*)s->profile)+offset, n);
763 return n;
764
765 case Qnote:
766 qlock(&p->debug);
767 if(waserror()){
768 qunlock(&p->debug);
769 nexterror();
770 }
771 if(p->pid != PID(c->qid))
772 error(Eprocdied);
773 if(n < 1) /* must accept at least the '\0' */
774 error(Etoosmall);
775 if(p->nnote == 0)
776 n = 0;
777 else {
778 m = strlen(p->note[0].msg) + 1;
779 if(m > n)
780 m = n;
781 memmove(va, p->note[0].msg, m);
782 ((char*)va)[m-1] = '\0';
783 p->nnote--;
784 memmove(p->note, p->note+1, p->nnote*sizeof(Note));
785 n = m;
786 }
787 if(p->nnote == 0)
788 p->notepending = 0;
789 poperror();
790 qunlock(&p->debug);
791 return n;
792
793 case Qproc:
794 if(offset >= sizeof(Proc))
795 return 0;
796 if(offset+n > sizeof(Proc))
797 n = sizeof(Proc) - offset;
798 memmove(a, ((char*)p)+offset, n);
799 return n;
800
801 case Qregs:
802 rptr = (uchar*)p->dbgreg;
803 rsize = sizeof(Ureg);
804 goto regread;
805
806 case Qkregs:
807 memset(&kur, 0, sizeof(Ureg));
808 setkernur(&kur, p);
809 rptr = (uchar*)&kur;
810 rsize = sizeof(Ureg);
811 goto regread;
812
813 case Qfpregs:
814 rptr = (uchar*)&p->fpsave;
815 rsize = sizeof(FPsave);
816 regread:
817 if(rptr == 0)
818 error(Enoreg);
819 if(offset >= rsize)
820 return 0;
821 if(offset+n > rsize)
822 n = rsize - offset;
823 memmove(a, rptr+offset, n);
824 return n;
825
826 case Qstatus:
827 if(offset >= STATSIZE)
828 return 0;
829 if(offset+n > STATSIZE)
830 n = STATSIZE - offset;
831
832 sps = p->psstate;
833 if(sps == 0)
834 sps = statename[p->state];
835 memset(statbuf, ' ', sizeof statbuf);
836 memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text));
837 memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user));
838 memmove(statbuf+2*KNAMELEN, sps, strlen(sps));
839 j = 2*KNAMELEN + 12;
840
841 for(i = 0; i < 6; i++) {
842 l = p->time[i];
843 if(i == TReal)
844 l = MACHP(0)->ticks - l;
845 l = TK2MS(l);
846 readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
847 }
848 /* ignore stack, which is mostly non-existent */
849 l = 0;
850 for(i=1; i<NSEG; i++){
851 s = p->seg[i];
852 if(s)
853 l += s->top - s->base;
854 }
855 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE);
856 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
857 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
858 memmove(a, statbuf+offset, n);
859 return n;
860
861 case Qsegment:
862 j = 0;
863 for(i = 0; i < NSEG; i++) {
864 sg = p->seg[i];
865 if(sg == 0)
866 continue;
867 j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n",
868 sname[sg->type&SG_TYPE],
869 sg->type&SG_RONLY ? 'R' : ' ',
870 sg->profile ? 'P' : ' ',
871 sg->base, sg->top, sg->ref);
872 }
873 if(offset >= j)
874 return 0;
875 if(offset+n > j)
876 n = j-offset;
877 if(n == 0 && offset == 0)
878 exhausted("segments");
879 memmove(a, &statbuf[offset], n);
880 return n;
881
882 case Qwait:
883 if(!canqlock(&p->qwaitr))
884 error(Einuse);
885
886 if(waserror()) {
887 qunlock(&p->qwaitr);
888 nexterror();
889 }
890
891 lock(&p->exl);
892 if(up == p && p->nchild == 0 && p->waitq == 0) {
893 unlock(&p->exl);
894 error(Enochild);
895 }
896 pid = p->pid;
897 while(p->waitq == 0) {
898 unlock(&p->exl);
899 sleep(&p->waitr, haswaitq, p);
900 if(p->pid != pid)
901 error(Eprocdied);
902 lock(&p->exl);
903 }
904 wq = p->waitq;
905 p->waitq = wq->next;
906 p->nwait--;
907 unlock(&p->exl);
908
909 qunlock(&p->qwaitr);
910 poperror();
911 n = snprint(a, n, "%d %lud %lud %lud %q",
912 wq->w.pid,
913 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
914 wq->w.msg);
915 free(wq);
916 return n;
917
918 case Qns:
919 qlock(&p->debug);
920 if(waserror()){
921 qunlock(&p->debug);
922 nexterror();
923 }
924 if(p->pgrp == nil || p->pid != PID(c->qid))
925 error(Eprocdied);
926 mw = c->aux;
927 if(mw->cddone){
928 qunlock(&p->debug);
929 poperror();
930 return 0;
931 }
932 mntscan(mw, p);
933 if(mw->mh == 0){
934 mw->cddone = 1;
935 i = snprint(a, n, "cd %s\n", p->dot->path->s);
936 qunlock(&p->debug);
937 poperror();
938 return i;
939 }
940 int2flag(mw->cm->mflag, flag);
941 if(strcmp(mw->cm->to->path->s, "#M") == 0){
942 srv = srvname(mw->cm->to->mchan);
943 i = snprint(a, n, "mount %s %s %s %s\n", flag,
944 srv==nil? mw->cm->to->mchan->path->s : srv,
945 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
946 free(srv);
947 }else
948 i = snprint(a, n, "bind %s %s %s\n", flag,
949 mw->cm->to->path->s, mw->mh->from->path->s);
950 qunlock(&p->debug);
951 poperror();
952 return i;
953
954 case Qnoteid:
955 return readnum(offset, va, n, p->noteid, NUMSIZE);
956 case Qfd:
957 return procfds(p, va, n, offset);
958 }
959 error(Egreg);
960 return 0; /* not reached */
961 }
962
963 void
964 mntscan(Mntwalk *mw, Proc *p)
965 {
966 Pgrp *pg;
967 Mount *t;
968 Mhead *f;
969 int nxt, i;
970 ulong last, bestmid;
971
972 pg = p->pgrp;
973 rlock(&pg->ns);
974
975 nxt = 0;
976 bestmid = ~0;
977
978 last = 0;
979 if(mw->mh)
980 last = mw->cm->mountid;
981
982 for(i = 0; i < MNTHASH; i++) {
983 for(f = pg->mnthash[i]; f; f = f->hash) {
984 for(t = f->mount; t; t = t->next) {
985 if(mw->mh == 0 ||
986 (t->mountid > last && t->mountid < bestmid)) {
987 mw->cm = t;
988 mw->mh = f;
989 bestmid = mw->cm->mountid;
990 nxt = 1;
991 }
992 }
993 }
994 }
995 if(nxt == 0)
996 mw->mh = 0;
997
998 runlock(&pg->ns);
999 }
1000
1001 static long
1002 procwrite(Chan *c, void *va, long n, vlong off)
1003 {
1004 int id, m;
1005 Proc *p, *t, *et;
1006 char *a, *arg, buf[ERRMAX];
1007 ulong offset = off;
1008
1009 a = va;
1010 if(c->qid.type & QTDIR)
1011 error(Eisdir);
1012
1013 p = proctab(SLOT(c->qid));
1014
1015 /* Use the remembered noteid in the channel rather
1016 * than the process pgrpid
1017 */
1018 if(QID(c->qid) == Qnotepg) {
1019 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1020 return n;
1021 }
1022
1023 qlock(&p->debug);
1024 if(waserror()){
1025 qunlock(&p->debug);
1026 nexterror();
1027 }
1028 if(p->pid != PID(c->qid))
1029 error(Eprocdied);
1030
1031 switch(QID(c->qid)){
1032 case Qargs:
1033 if(n == 0)
1034 error(Eshort);
1035 if(n >= ERRMAX)
1036 error(Etoobig);
1037 arg = malloc(n+1);
1038 if(arg == nil)
1039 error(Enomem);
1040 memmove(arg, va, n);
1041 m = n;
1042 if(arg[m-1] != 0)
1043 arg[m++] = 0;
1044 free(p->args);
1045 p->nargs = m;
1046 p->args = arg;
1047 p->setargs = 1;
1048 break;
1049
1050 case Qmem:
1051 if(p->state != Stopped)
1052 error(Ebadctl);
1053
1054 n = procctlmemio(p, offset, n, va, 0);
1055 break;
1056
1057 case Qregs:
1058 if(offset >= sizeof(Ureg))
1059 n = 0;
1060 else if(offset+n > sizeof(Ureg))
1061 n = sizeof(Ureg) - offset;
1062 if(p->dbgreg == 0)
1063 error(Enoreg);
1064 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1065 break;
1066
1067 case Qfpregs:
1068 if(offset >= sizeof(FPsave))
1069 n = 0;
1070 else if(offset+n > sizeof(FPsave))
1071 n = sizeof(FPsave) - offset;
1072 memmove((uchar*)&p->fpsave+offset, va, n);
1073 break;
1074
1075 case Qctl:
1076 procctlreq(p, va, n);
1077 break;
1078
1079 case Qnote:
1080 if(p->kp)
1081 error(Eperm);
1082 if(n >= ERRMAX-1)
1083 error(Etoobig);
1084 memmove(buf, va, n);
1085 buf[n] = 0;
1086 if(!postnote(p, 0, buf, NUser))
1087 error("note not posted");
1088 break;
1089 case Qnoteid:
1090 id = atoi(a);
1091 if(id == p->pid) {
1092 p->noteid = id;
1093 break;
1094 }
1095 t = proctab(0);
1096 for(et = t+conf.nproc; t < et; t++) {
1097 if(t->state == Dead)
1098 continue;
1099 if(id == t->noteid) {
1100 if(strcmp(p->user, t->user) != 0)
1101 error(Eperm);
1102 p->noteid = id;
1103 break;
1104 }
1105 }
1106 if(p->noteid != id)
1107 error(Ebadarg);
1108 break;
1109 default:
1110 pprint("unknown qid in procwrite\n");
1111 error(Egreg);
1112 }
1113 poperror();
1114 qunlock(&p->debug);
1115 return n;
1116 }
1117
1118 Dev procdevtab = {
1119 'p',
1120 "proc",
1121
1122 devreset,
1123 procinit,
1124 devshutdown,
1125 procattach,
1126 procwalk,
1127 procstat,
1128 procopen,
1129 devcreate,
1130 procclose,
1131 procread,
1132 devbread,
1133 procwrite,
1134 devbwrite,
1135 devremove,
1136 procwstat,
1137 };
1138
1139 Chan*
1140 proctext(Chan *c, Proc *p)
1141 {
1142 Chan *tc;
1143 Image *i;
1144 Segment *s;
1145
1146 s = p->seg[TSEG];
1147 if(s == 0)
1148 error(Enonexist);
1149 if(p->state==Dead)
1150 error(Eprocdied);
1151
1152 lock(s);
1153 i = s->image;
1154 if(i == 0) {
1155 unlock(s);
1156 error(Eprocdied);
1157 }
1158 unlock(s);
1159
1160 lock(i);
1161 if(waserror()) {
1162 unlock(i);
1163 nexterror();
1164 }
1165
1166 tc = i->c;
1167 if(tc == 0)
1168 error(Eprocdied);
1169
1170 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1171 cclose(tc);
1172 error(Eprocdied);
1173 }
1174
1175 if(p->pid != PID(c->qid))
1176 error(Eprocdied);
1177
1178 unlock(i);
1179 poperror();
1180
1181 return tc;
1182 }
1183
1184 void
1185 procstopwait(Proc *p, int ctl)
1186 {
1187 int pid;
1188
1189 if(p->pdbg)
1190 error(Einuse);
1191 if(procstopped(p) || p->state == Broken)
1192 return;
1193
1194 if(ctl != 0)
1195 p->procctl = ctl;
1196 p->pdbg = up;
1197 pid = p->pid;
1198 qunlock(&p->debug);
1199 up->psstate = "Stopwait";
1200 if(waserror()) {
1201 p->pdbg = 0;
1202 qlock(&p->debug);
1203 nexterror();
1204 }
1205 sleep(&up->sleep, procstopped, p);
1206 poperror();
1207 qlock(&p->debug);
1208 if(p->pid != pid)
1209 error(Eprocdied);
1210 }
1211
1212 static void
1213 procctlcloseone(Proc *p, Fgrp *f, int fd)
1214 {
1215 Chan *c;
1216
1217 c = f->fd[fd];
1218 if(c == nil)
1219 return;
1220 f->fd[fd] = nil;
1221 unlock(f);
1222 qunlock(&p->debug);
1223 cclose(c);
1224 qlock(&p->debug);
1225 lock(f);
1226 }
1227
1228 void
1229 procctlclosefiles(Proc *p, int all, int fd)
1230 {
1231 int i;
1232 Fgrp *f;
1233
1234 f = p->fgrp;
1235 if(f == nil)
1236 error(Eprocdied);
1237
1238 lock(f);
1239 f->ref++;
1240 if(all)
1241 for(i = 0; i < f->maxfd; i++)
1242 procctlcloseone(p, f, i);
1243 else
1244 procctlcloseone(p, f, fd);
1245 unlock(f);
1246 closefgrp(f);
1247 }
1248
1249 static char *
1250 parsetime(vlong *rt, char *s)
1251 {
1252 uvlong ticks;
1253 ulong l;
1254 char *e, *p;
1255 static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1256
1257 if (s == nil)
1258 return("missing value");
1259 ticks=strtoul(s, &e, 10);
1260 if (*e == '.'){
1261 p = e+1;
1262 l = strtoul(p, &e, 10);
1263 if(e-p > nelem(p10))
1264 return "too many digits after decimal point";
1265 if(e-p == 0)
1266 return "ill-formed number";
1267 l *= p10[e-p-1];
1268 }else
1269 l = 0;
1270 if (*e == '\0' || strcmp(e, "s") == 0){
1271 ticks = 1000000000 * ticks + l;
1272 }else if (strcmp(e, "ms") == 0){
1273 ticks = 1000000 * ticks + l/1000;
1274 }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1275 ticks = 1000 * ticks + l/1000000;
1276 }else if (strcmp(e, "ns") != 0)
1277 return "unrecognized unit";
1278 *rt = ticks;
1279 return nil;
1280 }
1281
1282 void
1283 procctlreq(Proc *p, char *va, int n)
1284 {
1285 Segment *s;
1286 int npc, pri;
1287 Cmdbuf *cb;
1288 Cmdtab *ct;
1289 vlong time;
1290 char *e;
1291 void (*pt)(Proc*, int, vlong);
1292
1293 if(p->kp) /* no ctl requests to kprocs */
1294 error(Eperm);
1295
1296 cb = parsecmd(va, n);
1297 if(waserror()){
1298 free(cb);
1299 nexterror();
1300 }
1301
1302 ct = lookupcmd(cb, proccmd, nelem(proccmd));
1303
1304 switch(ct->index){
1305 case CMclose:
1306 procctlclosefiles(p, 0, atoi(cb->f[1]));
1307 break;
1308 case CMclosefiles:
1309 procctlclosefiles(p, 1, 0);
1310 break;
1311 case CMhang:
1312 p->hang = 1;
1313 break;
1314 case CMkill:
1315 switch(p->state) {
1316 case Broken:
1317 unbreak(p);
1318 break;
1319 case Stopped:
1320 p->procctl = Proc_exitme;
1321 postnote(p, 0, "sys: killed", NExit);
1322 ready(p);
1323 break;
1324 default:
1325 p->procctl = Proc_exitme;
1326 postnote(p, 0, "sys: killed", NExit);
1327 }
1328 break;
1329 case CMnohang:
1330 p->hang = 0;
1331 break;
1332 case CMnoswap:
1333 p->noswap = 1;
1334 break;
1335 case CMpri:
1336 pri = atoi(cb->f[1]);
1337 if(pri > PriNormal && !iseve())
1338 error(Eperm);
1339 procpriority(p, pri, 0);
1340 break;
1341 case CMfixedpri:
1342 pri = atoi(cb->f[1]);
1343 if(pri > PriNormal && !iseve())
1344 error(Eperm);
1345 procpriority(p, pri, 1);
1346 break;
1347 case CMprivate:
1348 p->privatemem = 1;
1349 break;
1350 case CMprofile:
1351 s = p->seg[TSEG];
1352 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1353 error(Ebadctl);
1354 if(s->profile != 0)
1355 free(s->profile);
1356 npc = (s->top-s->base)>>LRESPROF;
1357 s->profile = malloc(npc*sizeof(*s->profile));
1358 if(s->profile == 0)
1359 error(Enomem);
1360 break;
1361 case CMstart:
1362 if(p->state != Stopped)
1363 error(Ebadctl);
1364 ready(p);
1365 break;
1366 case CMstartstop:
1367 if(p->state != Stopped)
1368 error(Ebadctl);
1369 p->procctl = Proc_traceme;
1370 ready(p);
1371 procstopwait(p, Proc_traceme);
1372 break;
1373 case CMstartsyscall:
1374 if(p->state != Stopped)
1375 error(Ebadctl);
1376 p->procctl = Proc_tracesyscall;
1377 ready(p);
1378 procstopwait(p, Proc_tracesyscall);
1379 break;
1380 case CMstop:
1381 procstopwait(p, Proc_stopme);
1382 break;
1383 case CMwaitstop:
1384 procstopwait(p, 0);
1385 break;
1386 case CMwired:
1387 procwired(p, atoi(cb->f[1]));
1388 break;
1389 case CMtrace:
1390 switch(cb->nf){
1391 case 1:
1392 p->trace ^= 1;
1393 break;
1394 case 2:
1395 p->trace = (atoi(cb->f[1]) != 0);
1396 break;
1397 default:
1398 error("args");
1399 }
1400 break;
1401 /* real time */
1402 case CMperiod:
1403 if(p->edf == nil)
1404 edfinit(p);
1405 if(e=parsetime(&time, cb->f[1])) /* time in ns */
1406 error(e);
1407 edfstop(p);
1408 p->edf->T = time/1000; /* Edf times are in µs */
1409 break;
1410 case CMdeadline:
1411 if(p->edf == nil)
1412 edfinit(p);
1413 if(e=parsetime(&time, cb->f[1]))
1414 error(e);
1415 edfstop(p);
1416 p->edf->D = time/1000;
1417 break;
1418 case CMcost:
1419 if(p->edf == nil)
1420 edfinit(p);
1421 if(e=parsetime(&time, cb->f[1]))
1422 error(e);
1423 edfstop(p);
1424 p->edf->C = time/1000;
1425 break;
1426 case CMsporadic:
1427 if(p->edf == nil)
1428 edfinit(p);
1429 p->edf->flags |= Sporadic;
1430 break;
1431 case CMdeadlinenotes:
1432 if(p->edf == nil)
1433 edfinit(p);
1434 p->edf->flags |= Sendnotes;
1435 break;
1436 case CMadmit:
1437 if(p->edf == 0)
1438 error("edf params");
1439 if(e = edfadmit(p))
1440 error(e);
1441 break;
1442 case CMextra:
1443 if(p->edf == nil)
1444 edfinit(p);
1445 p->edf->flags |= Extratime;
1446 break;
1447 case CMexpel:
1448 if(p->edf)
1449 edfstop(p);
1450 break;
1451 case CMevent:
1452 pt = proctrace;
1453 if(up->trace && pt)
1454 pt(up, SUser, 0);
1455 break;
1456 }
1457
1458 poperror();
1459 free(cb);
1460 }
1461
1462 int
1463 procstopped(void *a)
1464 {
1465 Proc *p = a;
1466 return p->state == Stopped;
1467 }
1468
1469 int
1470 procctlmemio(Proc *p, ulong offset, int n, void *va, int read)
1471 {
1472 KMap *k;
1473 Pte *pte;
1474 Page *pg;
1475 Segment *s;
1476 ulong soff, l;
1477 char *a = va, *b;
1478
1479 for(;;) {
1480 s = seg(p, offset, 1);
1481 if(s == 0)
1482 error(Ebadarg);
1483
1484 if(offset+n >= s->top)
1485 n = s->top-offset;
1486
1487 if(!read && (s->type&SG_TYPE) == SG_TEXT)
1488 s = txt2data(p, s);
1489
1490 s->steal++;
1491 soff = offset-s->base;
1492 if(waserror()) {
1493 s->steal--;
1494 nexterror();
1495 }
1496 if(fixfault(s, offset, read, 0) == 0)
1497 break;
1498 poperror();
1499 s->steal--;
1500 }
1501 poperror();
1502 pte = s->map[soff/PTEMAPMEM];
1503 if(pte == 0)
1504 panic("procctlmemio");
1505 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1506 if(pagedout(pg))
1507 panic("procctlmemio1");
1508
1509 l = BY2PG - (offset&(BY2PG-1));
1510 if(n > l)
1511 n = l;
1512
1513 k = kmap(pg);
1514 if(waserror()) {
1515 s->steal--;
1516 kunmap(k);
1517 nexterror();
1518 }
1519 b = (char*)VA(k);
1520 b += offset&(BY2PG-1);
1521 if(read == 1)
1522 memmove(a, b, n); /* This can fault */
1523 else
1524 memmove(b, a, n);
1525 kunmap(k);
1526 poperror();
1527
1528 /* Ensure the process sees text page changes */
1529 if(s->flushme)
1530 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1531
1532 s->steal--;
1533
1534 if(read == 0)
1535 p->newtlb = 1;
1536
1537 return n;
1538 }
1539
1540 Segment*
1541 txt2data(Proc *p, Segment *s)
1542 {
1543 int i;
1544 Segment *ps;
1545
1546 ps = newseg(SG_DATA, s->base, s->size);
1547 ps->image = s->image;
1548 incref(ps->image);
1549 ps->fstart = s->fstart;
1550 ps->flen = s->flen;
1551 ps->flushme = 1;
1552
1553 qlock(&p->seglock);
1554 for(i = 0; i < NSEG; i++)
1555 if(p->seg[i] == s)
1556 break;
1557 if(i == NSEG)
1558 panic("segment gone");
1559
1560 qunlock(&s->lk);
1561 putseg(s);
1562 qlock(&ps->lk);
1563 p->seg[i] = ps;
1564 qunlock(&p->seglock);
1565
1566 return ps;
1567 }
1568
1569 Segment*
1570 data2txt(Segment *s)
1571 {
1572 Segment *ps;
1573
1574 ps = newseg(SG_TEXT, s->base, s->size);
1575 ps->image = s->image;
1576 incref(ps->image);
1577 ps->fstart = s->fstart;
1578 ps->flen = s->flen;
1579 ps->flushme = 1;
1580
1581 return ps;
1582 }
Cache object: d064c5b234742f16b8368fa1daf49300
|