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 CMfair, 54 CMunfair, 55 CMtrace, 56 /* real time */ 57 CMperiod, 58 CMdeadline, 59 CMcost, 60 CMsporadic, 61 CMdeadlinenotes, 62 CMadmit, 63 CMexpel, 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 CMfair, "fair", 1, 117 CMunfair, "unfair", 1, 118 CMtrace, "trace", 1, 119 CMperiod, "period", 2, 120 CMdeadline, "deadline", 2, 121 CMcost, "cost", 2, 122 CMsporadic, "sporadic", 1, 123 CMdeadlinenotes, "deadlinenotes", 1, 124 CMadmit, "admit", 1, 125 CMexpel, "expel", 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 static Rendez teventr; 158 void (*proctrace)(Proc*, int); 159 160 extern int unfair; 161 162 static void 163 profclock(Ureg *ur, Timer *) 164 { 165 Tos *tos; 166 167 if(up == 0 || up->state != Running) 168 return; 169 170 /* user profiling clock */ 171 if(userureg(ur)){ 172 tos = (Tos*)(USTKTOP-sizeof(Tos)); 173 tos->clock += TK2MS(1); 174 segclock(ur->pc); 175 } 176 } 177 178 static int 179 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) 180 { 181 Qid qid; 182 Proc *p; 183 char *ename; 184 Segment *q; 185 ulong pid, path, perm, len; 186 187 if(s == DEVDOTDOT){ 188 mkqid(&qid, Qdir, 0, QTDIR); 189 devdir(c, qid, "#p", 0, eve, 0555, dp); 190 return 1; 191 } 192 193 if(c->qid.path == Qdir){ 194 if(s == 0){ 195 strcpy(up->genbuf, "trace"); 196 mkqid(&qid, Qtrace, -1, QTFILE); 197 devdir(c, qid, up->genbuf, 0, eve, 0444, dp); 198 return 1; 199 } 200 201 if(name != nil){ 202 /* ignore s and use name to find pid */ 203 pid = strtol(name, &ename, 10); 204 if(pid==0 || ename[0]!='\0') 205 return -1; 206 s = procindex(pid); 207 if(s < 0) 208 return -1; 209 } 210 else if(--s >= conf.nproc) 211 return -1; 212 213 p = proctab(s); 214 pid = p->pid; 215 if(pid == 0) 216 return 0; 217 sprint(up->genbuf, "%lud", pid); 218 /* 219 * String comparison is done in devwalk so name must match its formatted pid 220 */ 221 if(name != nil && strcmp(name, up->genbuf) != 0) 222 return -1; 223 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR); 224 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp); 225 return 1; 226 } 227 228 if(c->qid.path == Qtrace){ 229 strcpy(up->genbuf, "trace"); 230 mkqid(&qid, Qtrace, -1, QTFILE); 231 devdir(c, qid, up->genbuf, 0, eve, 0444, dp); 232 return 1; 233 } 234 235 if(--s >= nelem(procdir)) 236 return -1; 237 if(tab) 238 panic("procgen"); 239 240 tab = &procdir[s]; 241 path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */ 242 243 p = proctab(SLOT(c->qid)); 244 perm = tab->perm; 245 if(perm == 0) 246 perm = p->procmode; 247 else /* just copy read bits */ 248 perm |= p->procmode & 0444; 249 250 len = tab->length; 251 switch(QID(c->qid)) { 252 case Qwait: 253 len = p->nwait; /* incorrect size, but >0 means there's something to read */ 254 break; 255 case Qprofile: 256 q = p->seg[TSEG]; 257 if(q && q->profile) { 258 len = (q->top-q->base)>>LRESPROF; 259 len *= sizeof(*q->profile); 260 } 261 break; 262 } 263 264 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); 265 devdir(c, qid, tab->name, len, p->user, perm, dp); 266 return 1; 267 } 268 269 static void 270 _proctrace(Proc*p, Tevent etype) 271 { 272 Traceevent *te; 273 274 if (p->trace == 0 || topens == 0 || 275 (tproduced - tconsumed >= Nevents)) 276 return; 277 278 te = &tevents[tproduced&Emask]; 279 te->pid = p->pid; 280 te->etype = etype; 281 te->time = todget(nil); 282 tproduced++; 283 284 /* To avoid circular wakeup when used in combination with 285 * EDF scheduling. 286 */ 287 if (teventr.p && teventr.p->state == Wakeme) 288 wakeup(&teventr); 289 } 290 291 static void 292 procinit(void) 293 { 294 if(conf.nproc >= (1<<(16-QSHIFT))-1) 295 print("warning: too many procs for devproc\n"); 296 addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */ 297 } 298 299 static Chan* 300 procattach(char *spec) 301 { 302 return devattach('p', spec); 303 } 304 305 static Walkqid* 306 procwalk(Chan *c, Chan *nc, char **name, int nname) 307 { 308 return devwalk(c, nc, name, nname, 0, 0, procgen); 309 } 310 311 static int 312 procstat(Chan *c, uchar *db, int n) 313 { 314 return devstat(c, db, n, 0, 0, procgen); 315 } 316 317 /* 318 * none can't read or write state on other 319 * processes. This is to contain access of 320 * servers running as none should they be 321 * subverted by, for example, a stack attack. 322 */ 323 static void 324 nonone(Proc *p) 325 { 326 if(p == up) 327 return; 328 if(strcmp(up->user, "none") != 0) 329 return; 330 if(iseve()) 331 return; 332 error(Eperm); 333 } 334 335 static Chan* 336 procopen(Chan *c, int omode) 337 { 338 Proc *p; 339 Pgrp *pg; 340 Chan *tc; 341 int pid; 342 343 if(c->qid.type & QTDIR) 344 return devopen(c, omode, 0, 0, procgen); 345 346 if(QID(c->qid) == Qtrace){ 347 if (omode != OREAD) 348 error(Eperm); 349 lock(&tlock); 350 if (waserror()){ 351 unlock(&tlock); 352 nexterror(); 353 } 354 if (topens > 0) 355 error("already open"); 356 topens++; 357 if (tevents == nil){ 358 tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents); 359 if(tevents == nil) 360 error(Enomem); 361 tproduced = tconsumed = 0; 362 } 363 proctrace = _proctrace; 364 unlock(&tlock); 365 poperror(); 366 367 c->mode = openmode(omode); 368 c->flag |= COPEN; 369 c->offset = 0; 370 return c; 371 } 372 373 p = proctab(SLOT(c->qid)); 374 qlock(&p->debug); 375 if(waserror()){ 376 qunlock(&p->debug); 377 nexterror(); 378 } 379 pid = PID(c->qid); 380 if(p->pid != pid) 381 error(Eprocdied); 382 383 omode = openmode(omode); 384 385 switch(QID(c->qid)){ 386 case Qtext: 387 if(omode != OREAD) 388 error(Eperm); 389 tc = proctext(c, p); 390 tc->offset = 0; 391 qunlock(&p->debug); 392 poperror(); 393 return tc; 394 395 case Qproc: 396 case Qkregs: 397 case Qsegment: 398 case Qprofile: 399 case Qfd: 400 if(omode != OREAD) 401 error(Eperm); 402 break; 403 404 case Qmem: 405 case Qnote: 406 case Qctl: 407 if(p->privatemem) 408 error(Eperm); 409 /* fall through */ 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->name->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->name->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 int m, navail, ne; 671 long l; 672 Proc *p; 673 Waitq *wq; 674 Ureg kur; 675 uchar *rptr; 676 Mntwalk *mw; 677 Segment *sg, *s; 678 char *a = va, *sps; 679 int i, j, rsize, pid; 680 char statbuf[NSEG*32], *srv, flag[10]; 681 ulong offset = off; 682 683 if(c->qid.type & QTDIR) 684 return devdirread(c, a, n, 0, 0, procgen); 685 686 if(QID(c->qid) == Qtrace){ 687 if(!eventsavailable(nil)) 688 return 0; 689 690 rptr = (uchar*)va; 691 navail = tproduced - tconsumed; 692 if(navail > n / sizeof(Traceevent)) 693 navail = n / sizeof(Traceevent); 694 while(navail > 0) { 695 ne = ((tconsumed & Emask) + navail > Nevents)? 696 Nevents - (tconsumed & Emask): navail; 697 memmove(rptr, &tevents[tconsumed & Emask], 698 ne * sizeof(Traceevent)); 699 700 tconsumed += ne; 701 rptr += ne * sizeof(Traceevent); 702 navail -= ne; 703 } 704 return rptr - (uchar*)va; 705 } 706 707 p = proctab(SLOT(c->qid)); 708 if(p->pid != PID(c->qid)) 709 error(Eprocdied); 710 711 switch(QID(c->qid)){ 712 case Qargs: 713 qlock(&p->debug); 714 j = procargs(p, p->genbuf, sizeof p->genbuf); 715 qunlock(&p->debug); 716 if(offset >= j) 717 return 0; 718 if(offset+n > j) 719 n = j-offset; 720 memmove(a, &p->genbuf[offset], n); 721 return n; 722 723 case Qmem: 724 if(offset < KZERO 725 || (offset >= USTKTOP-USTKSIZE && offset < USTKTOP)) 726 return procctlmemio(p, offset, n, va, 1); 727 728 if(!iseve()) 729 error(Eperm); 730 731 /* validate kernel addresses */ 732 if(offset < (ulong)end) { 733 if(offset+n > (ulong)end) 734 n = (ulong)end - offset; 735 memmove(a, (char*)offset, n); 736 return n; 737 } 738 /* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */ 739 if(offset >= conf.base0 && offset < conf.npage0){ 740 if(offset+n > conf.npage0) 741 n = conf.npage0 - offset; 742 memmove(a, (char*)offset, n); 743 return n; 744 } 745 if(offset >= conf.base1 && offset < conf.npage1){ 746 if(offset+n > conf.npage1) 747 n = conf.npage1 - offset; 748 memmove(a, (char*)offset, n); 749 return n; 750 } 751 error(Ebadarg); 752 753 case Qprofile: 754 s = p->seg[TSEG]; 755 if(s == 0 || s->profile == 0) 756 error("profile is off"); 757 i = (s->top-s->base)>>LRESPROF; 758 i *= sizeof(*s->profile); 759 if(offset >= i) 760 return 0; 761 if(offset+n > i) 762 n = i - offset; 763 memmove(a, ((char*)s->profile)+offset, n); 764 return n; 765 766 case Qnote: 767 qlock(&p->debug); 768 if(waserror()){ 769 qunlock(&p->debug); 770 nexterror(); 771 } 772 if(p->pid != PID(c->qid)) 773 error(Eprocdied); 774 if(n < 1) /* must accept at least the '\0' */ 775 error(Etoosmall); 776 if(p->nnote == 0) 777 n = 0; 778 else { 779 m = strlen(p->note[0].msg) + 1; 780 if(m > n) 781 m = n; 782 memmove(va, p->note[0].msg, m); 783 ((char*)va)[m-1] = '\0'; 784 p->nnote--; 785 memmove(p->note, p->note+1, p->nnote*sizeof(Note)); 786 n = m; 787 } 788 if(p->nnote == 0) 789 p->notepending = 0; 790 poperror(); 791 qunlock(&p->debug); 792 return n; 793 794 case Qproc: 795 if(offset >= sizeof(Proc)) 796 return 0; 797 if(offset+n > sizeof(Proc)) 798 n = sizeof(Proc) - offset; 799 memmove(a, ((char*)p)+offset, n); 800 return n; 801 802 case Qregs: 803 rptr = (uchar*)p->dbgreg; 804 rsize = sizeof(Ureg); 805 goto regread; 806 807 case Qkregs: 808 memset(&kur, 0, sizeof(Ureg)); 809 setkernur(&kur, p); 810 rptr = (uchar*)&kur; 811 rsize = sizeof(Ureg); 812 goto regread; 813 814 case Qfpregs: 815 rptr = (uchar*)&p->fpsave; 816 rsize = sizeof(FPsave); 817 regread: 818 if(rptr == 0) 819 error(Enoreg); 820 if(offset >= rsize) 821 return 0; 822 if(offset+n > rsize) 823 n = rsize - offset; 824 memmove(a, rptr+offset, n); 825 return n; 826 827 case Qstatus: 828 if(offset >= STATSIZE) 829 return 0; 830 if(offset+n > STATSIZE) 831 n = STATSIZE - offset; 832 833 sps = p->psstate; 834 if(sps == 0) 835 sps = statename[p->state]; 836 memset(statbuf, ' ', sizeof statbuf); 837 memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text)); 838 memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user)); 839 memmove(statbuf+2*KNAMELEN, sps, strlen(sps)); 840 j = 2*KNAMELEN + 12; 841 842 for(i = 0; i < 6; i++) { 843 l = p->time[i]; 844 if(i == TReal) 845 l = MACHP(0)->ticks - l; 846 l = TK2MS(l); 847 readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 848 } 849 /* ignore stack, which is mostly non-existent */ 850 l = 0; 851 for(i=1; i<NSEG; i++){ 852 s = p->seg[i]; 853 if(s) 854 l += s->top - s->base; 855 } 856 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE); 857 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE); 858 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE); 859 memmove(a, statbuf+offset, n); 860 return n; 861 862 case Qsegment: 863 j = 0; 864 for(i = 0; i < NSEG; i++) { 865 sg = p->seg[i]; 866 if(sg == 0) 867 continue; 868 j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n", 869 sname[sg->type&SG_TYPE], 870 sg->type&SG_RONLY ? 'R' : ' ', 871 sg->profile ? 'P' : ' ', 872 sg->base, sg->top, sg->ref); 873 } 874 if(offset >= j) 875 return 0; 876 if(offset+n > j) 877 n = j-offset; 878 if(n == 0 && offset == 0) 879 exhausted("segments"); 880 memmove(a, &statbuf[offset], n); 881 return n; 882 883 case Qwait: 884 if(!canqlock(&p->qwaitr)) 885 error(Einuse); 886 887 if(waserror()) { 888 qunlock(&p->qwaitr); 889 nexterror(); 890 } 891 892 lock(&p->exl); 893 if(up == p && p->nchild == 0 && p->waitq == 0) { 894 unlock(&p->exl); 895 error(Enochild); 896 } 897 pid = p->pid; 898 while(p->waitq == 0) { 899 unlock(&p->exl); 900 sleep(&p->waitr, haswaitq, p); 901 if(p->pid != pid) 902 error(Eprocdied); 903 lock(&p->exl); 904 } 905 wq = p->waitq; 906 p->waitq = wq->next; 907 p->nwait--; 908 unlock(&p->exl); 909 910 qunlock(&p->qwaitr); 911 poperror(); 912 n = snprint(a, n, "%d %lud %lud %lud %q", 913 wq->w.pid, 914 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal], 915 wq->w.msg); 916 free(wq); 917 return n; 918 919 case Qns: 920 qlock(&p->debug); 921 if(waserror()){ 922 qunlock(&p->debug); 923 nexterror(); 924 } 925 if(p->pgrp == nil || p->pid != PID(c->qid)) 926 error(Eprocdied); 927 mw = c->aux; 928 if(mw->cddone){ 929 qunlock(&p->debug); 930 poperror(); 931 return 0; 932 } 933 mntscan(mw, p); 934 if(mw->mh == 0){ 935 mw->cddone = 1; 936 i = snprint(a, n, "cd %s\n", p->dot->name->s); 937 qunlock(&p->debug); 938 poperror(); 939 return i; 940 } 941 int2flag(mw->cm->mflag, flag); 942 if(strcmp(mw->cm->to->name->s, "#M") == 0){ 943 srv = srvname(mw->cm->to->mchan); 944 i = snprint(a, n, "mount %s %s %s %s\n", flag, 945 srv==nil? mw->cm->to->mchan->name->s : srv, 946 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : ""); 947 free(srv); 948 }else 949 i = snprint(a, n, "bind %s %s %s\n", flag, 950 mw->cm->to->name->s, mw->mh->from->name->s); 951 qunlock(&p->debug); 952 poperror(); 953 return i; 954 955 case Qnoteid: 956 return readnum(offset, va, n, p->noteid, NUMSIZE); 957 case Qfd: 958 return procfds(p, va, n, offset); 959 } 960 error(Egreg); 961 return 0; /* not reached */ 962 } 963 964 void 965 mntscan(Mntwalk *mw, Proc *p) 966 { 967 Pgrp *pg; 968 Mount *t; 969 Mhead *f; 970 int nxt, i; 971 ulong last, bestmid; 972 973 pg = p->pgrp; 974 rlock(&pg->ns); 975 976 nxt = 0; 977 bestmid = ~0; 978 979 last = 0; 980 if(mw->mh) 981 last = mw->cm->mountid; 982 983 for(i = 0; i < MNTHASH; i++) { 984 for(f = pg->mnthash[i]; f; f = f->hash) { 985 for(t = f->mount; t; t = t->next) { 986 if(mw->mh == 0 || 987 (t->mountid > last && t->mountid < bestmid)) { 988 mw->cm = t; 989 mw->mh = f; 990 bestmid = mw->cm->mountid; 991 nxt = 1; 992 } 993 } 994 } 995 } 996 if(nxt == 0) 997 mw->mh = 0; 998 999 runlock(&pg->ns); 1000 } 1001 1002 static long 1003 procwrite(Chan *c, void *va, long n, vlong off) 1004 { 1005 int id, m; 1006 Proc *p, *t, *et; 1007 char *a, *arg, buf[ERRMAX]; 1008 ulong offset = off; 1009 1010 a = va; 1011 if(c->qid.type & QTDIR) 1012 error(Eisdir); 1013 1014 p = proctab(SLOT(c->qid)); 1015 1016 /* Use the remembered noteid in the channel rather 1017 * than the process pgrpid 1018 */ 1019 if(QID(c->qid) == Qnotepg) { 1020 pgrpnote(NOTEID(c->pgrpid), va, n, NUser); 1021 return n; 1022 } 1023 1024 qlock(&p->debug); 1025 if(waserror()){ 1026 qunlock(&p->debug); 1027 nexterror(); 1028 } 1029 if(p->pid != PID(c->qid)) 1030 error(Eprocdied); 1031 1032 switch(QID(c->qid)){ 1033 case Qargs: 1034 if(n == 0) 1035 error(Eshort); 1036 if(n >= ERRMAX) 1037 error(Etoobig); 1038 arg = malloc(n+1); 1039 if(arg == nil) 1040 error(Enomem); 1041 memmove(arg, va, n); 1042 m = n; 1043 if(arg[m-1] != 0) 1044 arg[m++] = 0; 1045 free(p->args); 1046 p->nargs = m; 1047 p->args = arg; 1048 p->setargs = 1; 1049 break; 1050 1051 case Qmem: 1052 if(p->state != Stopped) 1053 error(Ebadctl); 1054 1055 n = procctlmemio(p, offset, n, va, 0); 1056 break; 1057 1058 case Qregs: 1059 if(offset >= sizeof(Ureg)) 1060 return 0; 1061 if(offset+n > sizeof(Ureg)) 1062 n = sizeof(Ureg) - offset; 1063 if(p->dbgreg == 0) 1064 error(Enoreg); 1065 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n); 1066 break; 1067 1068 case Qfpregs: 1069 if(offset >= sizeof(FPsave)) 1070 return 0; 1071 if(offset+n > sizeof(FPsave)) 1072 n = sizeof(FPsave) - offset; 1073 memmove((uchar*)&p->fpsave+offset, va, n); 1074 break; 1075 1076 case Qctl: 1077 procctlreq(p, va, n); 1078 break; 1079 1080 case Qnote: 1081 if(p->kp) 1082 error(Eperm); 1083 if(n >= ERRMAX-1) 1084 error(Etoobig); 1085 memmove(buf, va, n); 1086 buf[n] = 0; 1087 if(!postnote(p, 0, buf, NUser)) 1088 error("note not posted"); 1089 break; 1090 case Qnoteid: 1091 id = atoi(a); 1092 if(id == p->pid) { 1093 p->noteid = id; 1094 break; 1095 } 1096 t = proctab(0); 1097 for(et = t+conf.nproc; t < et; t++) { 1098 if(id == t->noteid) { 1099 if(strcmp(p->user, t->user) != 0) 1100 error(Eperm); 1101 p->noteid = id; 1102 break; 1103 } 1104 } 1105 if(p->noteid != id) 1106 error(Ebadarg); 1107 break; 1108 default: 1109 pprint("unknown qid in procwrite\n"); 1110 error(Egreg); 1111 } 1112 poperror(); 1113 qunlock(&p->debug); 1114 return n; 1115 } 1116 1117 Dev procdevtab = { 1118 'p', 1119 "proc", 1120 1121 devreset, 1122 procinit, 1123 devshutdown, 1124 procattach, 1125 procwalk, 1126 procstat, 1127 procopen, 1128 devcreate, 1129 procclose, 1130 procread, 1131 devbread, 1132 procwrite, 1133 devbwrite, 1134 devremove, 1135 procwstat, 1136 }; 1137 1138 Chan* 1139 proctext(Chan *c, Proc *p) 1140 { 1141 Chan *tc; 1142 Image *i; 1143 Segment *s; 1144 1145 s = p->seg[TSEG]; 1146 if(s == 0) 1147 error(Enonexist); 1148 if(p->state==Dead) 1149 error(Eprocdied); 1150 1151 lock(s); 1152 i = s->image; 1153 if(i == 0) { 1154 unlock(s); 1155 error(Eprocdied); 1156 } 1157 unlock(s); 1158 1159 lock(i); 1160 if(waserror()) { 1161 unlock(i); 1162 nexterror(); 1163 } 1164 1165 tc = i->c; 1166 if(tc == 0) 1167 error(Eprocdied); 1168 1169 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { 1170 cclose(tc); 1171 error(Eprocdied); 1172 } 1173 1174 if(p->pid != PID(c->qid)) 1175 error(Eprocdied); 1176 1177 unlock(i); 1178 poperror(); 1179 1180 return tc; 1181 } 1182 1183 void 1184 procstopwait(Proc *p, int ctl) 1185 { 1186 int pid; 1187 1188 if(p->pdbg) 1189 error(Einuse); 1190 if(procstopped(p) || p->state == Broken) 1191 return; 1192 1193 if(ctl != 0) 1194 p->procctl = ctl; 1195 p->pdbg = up; 1196 pid = p->pid; 1197 qunlock(&p->debug); 1198 up->psstate = "Stopwait"; 1199 if(waserror()) { 1200 p->pdbg = 0; 1201 qlock(&p->debug); 1202 nexterror(); 1203 } 1204 sleep(&up->sleep, procstopped, p); 1205 poperror(); 1206 qlock(&p->debug); 1207 if(p->pid != pid) 1208 error(Eprocdied); 1209 } 1210 1211 static void 1212 procctlcloseone(Proc *p, Fgrp *f, int fd) 1213 { 1214 Chan *c; 1215 1216 c = f->fd[fd]; 1217 if(c == nil) 1218 return; 1219 f->fd[fd] = nil; 1220 unlock(f); 1221 qunlock(&p->debug); 1222 cclose(c); 1223 qlock(&p->debug); 1224 lock(f); 1225 } 1226 1227 void 1228 procctlclosefiles(Proc *p, int all, int fd) 1229 { 1230 int i; 1231 Fgrp *f; 1232 1233 f = p->fgrp; 1234 if(f == nil) 1235 error(Eprocdied); 1236 1237 lock(f); 1238 f->ref++; 1239 if(all) 1240 for(i = 0; i < f->maxfd; i++) 1241 procctlcloseone(p, f, i); 1242 else 1243 procctlcloseone(p, f, fd); 1244 unlock(f); 1245 closefgrp(f); 1246 } 1247 1248 static char * 1249 parsetime(vlong *rt, char *s) 1250 { 1251 uvlong ticks; 1252 ulong l; 1253 char *e, *p; 1254 static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; 1255 1256 if (s == nil) 1257 return("missing value"); 1258 ticks=strtoul(s, &e, 10); 1259 if (*e == '.'){ 1260 p = e+1; 1261 l = strtoul(p, &e, 10); 1262 if(e-p > nelem(p10)) 1263 return "too many digits after decimal point"; 1264 if(e-p == 0) 1265 return "ill-formed number"; 1266 l *= p10[e-p-1]; 1267 }else 1268 l = 0; 1269 if (*e == '\0' || strcmp(e, "s") == 0){ 1270 ticks = 1000000000 * ticks + l; 1271 }else if (strcmp(e, "ms") == 0){ 1272 ticks = 1000000 * ticks + l/1000; 1273 }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){ 1274 ticks = 1000 * ticks + l/1000000; 1275 }else if (strcmp(e, "ns") != 0) 1276 return "unrecognized unit"; 1277 *rt = ticks; 1278 return nil; 1279 } 1280 1281 void 1282 procctlreq(Proc *p, char *va, int n) 1283 { 1284 Segment *s; 1285 int npc, pri; 1286 Cmdbuf *cb; 1287 Cmdtab *ct; 1288 vlong time; 1289 char *e; 1290 1291 if(p->kp) /* no ctl requests to kprocs */ 1292 error(Eperm); 1293 1294 cb = parsecmd(va, n); 1295 if(waserror()){ 1296 free(cb); 1297 nexterror(); 1298 } 1299 1300 ct = lookupcmd(cb, proccmd, nelem(proccmd)); 1301 1302 switch(ct->index){ 1303 case CMclose: 1304 procctlclosefiles(p, 0, atoi(cb->f[1])); 1305 break; 1306 case CMclosefiles: 1307 procctlclosefiles(p, 1, 0); 1308 break; 1309 case CMhang: 1310 p->hang = 1; 1311 break; 1312 case CMkill: 1313 switch(p->state) { 1314 case Broken: 1315 unbreak(p); 1316 break; 1317 case Stopped: 1318 postnote(p, 0, "sys: killed", NExit); 1319 p->procctl = Proc_exitme; 1320 ready(p); 1321 break; 1322 default: 1323 postnote(p, 0, "sys: killed", NExit); 1324 p->procctl = Proc_exitme; 1325 } 1326 break; 1327 case CMnohang: 1328 p->hang = 0; 1329 break; 1330 case CMnoswap: 1331 p->noswap = 1; 1332 break; 1333 case CMpri: 1334 pri = atoi(cb->f[1]); 1335 if(pri > PriNormal && !iseve()) 1336 error(Eperm); 1337 procpriority(p, pri, 0); 1338 break; 1339 case CMfixedpri: 1340 pri = atoi(cb->f[1]); 1341 if(pri > PriNormal && !iseve()) 1342 error(Eperm); 1343 procpriority(p, pri, 1); 1344 break; 1345 case CMprivate: 1346 p->privatemem = 1; 1347 break; 1348 case CMprofile: 1349 s = p->seg[TSEG]; 1350 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT) 1351 error(Ebadctl); 1352 if(s->profile != 0) 1353 free(s->profile); 1354 npc = (s->top-s->base)>>LRESPROF; 1355 s->profile = malloc(npc*sizeof(*s->profile)); 1356 if(s->profile == 0) 1357 error(Enomem); 1358 break; 1359 case CMstart: 1360 if(p->state != Stopped) 1361 error(Ebadctl); 1362 ready(p); 1363 break; 1364 case CMstartstop: 1365 if(p->state != Stopped) 1366 error(Ebadctl); 1367 p->procctl = Proc_traceme; 1368 ready(p); 1369 procstopwait(p, Proc_traceme); 1370 break; 1371 case CMstartsyscall: 1372 if(p->state != Stopped) 1373 error(Ebadctl); 1374 p->procctl = Proc_tracesyscall; 1375 ready(p); 1376 procstopwait(p, Proc_tracesyscall); 1377 break; 1378 case CMstop: 1379 procstopwait(p, Proc_stopme); 1380 break; 1381 case CMwaitstop: 1382 procstopwait(p, 0); 1383 break; 1384 case CMwired: 1385 procwired(p, atoi(cb->f[1])); 1386 break; 1387 case CMtrace: 1388 p->trace = (p->trace + 1) & 1; 1389 break; 1390 /* real time */ 1391 case CMperiod: 1392 if(p->edf == nil) 1393 edfinit(p); 1394 if(e=parsetime(&time, cb->f[1])) 1395 error(e); 1396 edfstop(p); 1397 p->edf->T = time; 1398 break; 1399 case CMdeadline: 1400 if(p->edf == nil) 1401 edfinit(p); 1402 if(e=parsetime(&time, cb->f[1])) 1403 error(e); 1404 edfstop(p); 1405 p->edf->D = time; 1406 break; 1407 case CMcost: 1408 if(p->edf == nil) 1409 edfinit(p); 1410 if(e=parsetime(&time, cb->f[1])) 1411 error(e); 1412 edfstop(p); 1413 p->edf->C = time; 1414 break; 1415 case CMsporadic: 1416 if(p->edf == nil) 1417 edfinit(p); 1418 p->edf->flags |= Sporadic; 1419 break; 1420 case CMdeadlinenotes: 1421 if(p->edf == nil) 1422 edfinit(p); 1423 p->edf->flags |= Sendnotes; 1424 break; 1425 case CMadmit: 1426 if(p->edf == 0) 1427 error("edf params"); 1428 if(e = edfadmit(p)) 1429 error(e); 1430 break; 1431 case CMexpel: 1432 if(p->edf) 1433 edfstop(p); 1434 break; 1435 } 1436 1437 poperror(); 1438 free(cb); 1439 } 1440 1441 int 1442 procstopped(void *a) 1443 { 1444 Proc *p = a; 1445 return p->state == Stopped; 1446 } 1447 1448 int 1449 procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 1450 { 1451 KMap *k; 1452 Pte *pte; 1453 Page *pg; 1454 Segment *s; 1455 ulong soff, l; 1456 char *a = va, *b; 1457 1458 for(;;) { 1459 s = seg(p, offset, 1); 1460 if(s == 0) 1461 error(Ebadarg); 1462 1463 if(offset+n >= s->top) 1464 n = s->top-offset; 1465 1466 if(!read && (s->type&SG_TYPE) == SG_TEXT) 1467 s = txt2data(p, s); 1468 1469 s->steal++; 1470 soff = offset-s->base; 1471 if(waserror()) { 1472 s->steal--; 1473 nexterror(); 1474 } 1475 if(fixfault(s, offset, read, 0) == 0) 1476 break; 1477 poperror(); 1478 s->steal--; 1479 } 1480 poperror(); 1481 pte = s->map[soff/PTEMAPMEM]; 1482 if(pte == 0) 1483 panic("procctlmemio"); 1484 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 1485 if(pagedout(pg)) 1486 panic("procctlmemio1"); 1487 1488 l = BY2PG - (offset&(BY2PG-1)); 1489 if(n > l) 1490 n = l; 1491 1492 k = kmap(pg); 1493 if(waserror()) { 1494 s->steal--; 1495 kunmap(k); 1496 nexterror(); 1497 } 1498 b = (char*)VA(k); 1499 b += offset&(BY2PG-1); 1500 if(read == 1) 1501 memmove(a, b, n); /* This can fault */ 1502 else 1503 memmove(b, a, n); 1504 kunmap(k); 1505 poperror(); 1506 1507 /* Ensure the process sees text page changes */ 1508 if(s->flushme) 1509 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 1510 1511 s->steal--; 1512 1513 if(read == 0) 1514 p->newtlb = 1; 1515 1516 return n; 1517 } 1518 1519 Segment* 1520 txt2data(Proc *p, Segment *s) 1521 { 1522 int i; 1523 Segment *ps; 1524 1525 ps = newseg(SG_DATA, s->base, s->size); 1526 ps->image = s->image; 1527 incref(ps->image); 1528 ps->fstart = s->fstart; 1529 ps->flen = s->flen; 1530 ps->flushme = 1; 1531 1532 qlock(&p->seglock); 1533 for(i = 0; i < NSEG; i++) 1534 if(p->seg[i] == s) 1535 break; 1536 if(p->seg[i] != s) 1537 panic("segment gone"); 1538 1539 qunlock(&s->lk); 1540 putseg(s); 1541 qlock(&ps->lk); 1542 p->seg[i] = ps; 1543 qunlock(&p->seglock); 1544 1545 return ps; 1546 } 1547 1548 Segment* 1549 data2txt(Segment *s) 1550 { 1551 Segment *ps; 1552 1553 ps = newseg(SG_TEXT, s->base, s->size); 1554 ps->image = s->image; 1555 incref(ps->image); 1556 ps->fstart = s->fstart; 1557 ps->flen = s->flen; 1558 ps->flushme = 1; 1559 1560 return ps; 1561 } 1562