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