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