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