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(t->state == Dead) 1101 continue; 1102 if(id == t->noteid) { 1103 if(strcmp(p->user, t->user) != 0) 1104 error(Eperm); 1105 p->noteid = id; 1106 break; 1107 } 1108 } 1109 if(p->noteid != id) 1110 error(Ebadarg); 1111 break; 1112 default: 1113 pprint("unknown qid in procwrite\n"); 1114 error(Egreg); 1115 } 1116 poperror(); 1117 qunlock(&p->debug); 1118 return n; 1119 } 1120 1121 Dev procdevtab = { 1122 'p', 1123 "proc", 1124 1125 devreset, 1126 procinit, 1127 devshutdown, 1128 procattach, 1129 procwalk, 1130 procstat, 1131 procopen, 1132 devcreate, 1133 procclose, 1134 procread, 1135 devbread, 1136 procwrite, 1137 devbwrite, 1138 devremove, 1139 procwstat, 1140 }; 1141 1142 Chan* 1143 proctext(Chan *c, Proc *p) 1144 { 1145 Chan *tc; 1146 Image *i; 1147 Segment *s; 1148 1149 s = p->seg[TSEG]; 1150 if(s == 0) 1151 error(Enonexist); 1152 if(p->state==Dead) 1153 error(Eprocdied); 1154 1155 lock(s); 1156 i = s->image; 1157 if(i == 0) { 1158 unlock(s); 1159 error(Eprocdied); 1160 } 1161 unlock(s); 1162 1163 lock(i); 1164 if(waserror()) { 1165 unlock(i); 1166 nexterror(); 1167 } 1168 1169 tc = i->c; 1170 if(tc == 0) 1171 error(Eprocdied); 1172 1173 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { 1174 cclose(tc); 1175 error(Eprocdied); 1176 } 1177 1178 if(p->pid != PID(c->qid)) 1179 error(Eprocdied); 1180 1181 unlock(i); 1182 poperror(); 1183 1184 return tc; 1185 } 1186 1187 void 1188 procstopwait(Proc *p, int ctl) 1189 { 1190 int pid; 1191 1192 if(p->pdbg) 1193 error(Einuse); 1194 if(procstopped(p) || p->state == Broken) 1195 return; 1196 1197 if(ctl != 0) 1198 p->procctl = ctl; 1199 p->pdbg = up; 1200 pid = p->pid; 1201 qunlock(&p->debug); 1202 up->psstate = "Stopwait"; 1203 if(waserror()) { 1204 p->pdbg = 0; 1205 qlock(&p->debug); 1206 nexterror(); 1207 } 1208 sleep(&up->sleep, procstopped, p); 1209 poperror(); 1210 qlock(&p->debug); 1211 if(p->pid != pid) 1212 error(Eprocdied); 1213 } 1214 1215 static void 1216 procctlcloseone(Proc *p, Fgrp *f, int fd) 1217 { 1218 Chan *c; 1219 1220 c = f->fd[fd]; 1221 if(c == nil) 1222 return; 1223 f->fd[fd] = nil; 1224 unlock(f); 1225 qunlock(&p->debug); 1226 cclose(c); 1227 qlock(&p->debug); 1228 lock(f); 1229 } 1230 1231 void 1232 procctlclosefiles(Proc *p, int all, int fd) 1233 { 1234 int i; 1235 Fgrp *f; 1236 1237 f = p->fgrp; 1238 if(f == nil) 1239 error(Eprocdied); 1240 1241 lock(f); 1242 f->ref++; 1243 if(all) 1244 for(i = 0; i < f->maxfd; i++) 1245 procctlcloseone(p, f, i); 1246 else 1247 procctlcloseone(p, f, fd); 1248 unlock(f); 1249 closefgrp(f); 1250 } 1251 1252 static char * 1253 parsetime(vlong *rt, char *s) 1254 { 1255 uvlong ticks; 1256 ulong l; 1257 char *e, *p; 1258 static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1}; 1259 1260 if (s == nil) 1261 return("missing value"); 1262 ticks=strtoul(s, &e, 10); 1263 if (*e == '.'){ 1264 p = e+1; 1265 l = strtoul(p, &e, 10); 1266 if(e-p > nelem(p10)) 1267 return "too many digits after decimal point"; 1268 if(e-p == 0) 1269 return "ill-formed number"; 1270 l *= p10[e-p-1]; 1271 }else 1272 l = 0; 1273 if (*e == '\0' || strcmp(e, "s") == 0){ 1274 ticks = 1000000000 * ticks + l; 1275 }else if (strcmp(e, "ms") == 0){ 1276 ticks = 1000000 * ticks + l/1000; 1277 }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){ 1278 ticks = 1000 * ticks + l/1000000; 1279 }else if (strcmp(e, "ns") != 0) 1280 return "unrecognized unit"; 1281 *rt = ticks; 1282 return nil; 1283 } 1284 1285 void 1286 procctlreq(Proc *p, char *va, int n) 1287 { 1288 Segment *s; 1289 int npc, pri; 1290 Cmdbuf *cb; 1291 Cmdtab *ct; 1292 vlong time; 1293 char *e; 1294 1295 if(p->kp) /* no ctl requests to kprocs */ 1296 error(Eperm); 1297 1298 cb = parsecmd(va, n); 1299 if(waserror()){ 1300 free(cb); 1301 nexterror(); 1302 } 1303 1304 ct = lookupcmd(cb, proccmd, nelem(proccmd)); 1305 1306 switch(ct->index){ 1307 case CMclose: 1308 procctlclosefiles(p, 0, atoi(cb->f[1])); 1309 break; 1310 case CMclosefiles: 1311 procctlclosefiles(p, 1, 0); 1312 break; 1313 case CMhang: 1314 p->hang = 1; 1315 break; 1316 case CMkill: 1317 switch(p->state) { 1318 case Broken: 1319 unbreak(p); 1320 break; 1321 case Stopped: 1322 postnote(p, 0, "sys: killed", NExit); 1323 p->procctl = Proc_exitme; 1324 ready(p); 1325 break; 1326 default: 1327 postnote(p, 0, "sys: killed", NExit); 1328 p->procctl = Proc_exitme; 1329 } 1330 break; 1331 case CMnohang: 1332 p->hang = 0; 1333 break; 1334 case CMnoswap: 1335 p->noswap = 1; 1336 break; 1337 case CMpri: 1338 pri = atoi(cb->f[1]); 1339 if(pri > PriNormal && !iseve()) 1340 error(Eperm); 1341 procpriority(p, pri, 0); 1342 break; 1343 case CMfixedpri: 1344 pri = atoi(cb->f[1]); 1345 if(pri > PriNormal && !iseve()) 1346 error(Eperm); 1347 procpriority(p, pri, 1); 1348 break; 1349 case CMprivate: 1350 p->privatemem = 1; 1351 break; 1352 case CMprofile: 1353 s = p->seg[TSEG]; 1354 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT) 1355 error(Ebadctl); 1356 if(s->profile != 0) 1357 free(s->profile); 1358 npc = (s->top-s->base)>>LRESPROF; 1359 s->profile = malloc(npc*sizeof(*s->profile)); 1360 if(s->profile == 0) 1361 error(Enomem); 1362 break; 1363 case CMstart: 1364 if(p->state != Stopped) 1365 error(Ebadctl); 1366 ready(p); 1367 break; 1368 case CMstartstop: 1369 if(p->state != Stopped) 1370 error(Ebadctl); 1371 p->procctl = Proc_traceme; 1372 ready(p); 1373 procstopwait(p, Proc_traceme); 1374 break; 1375 case CMstartsyscall: 1376 if(p->state != Stopped) 1377 error(Ebadctl); 1378 p->procctl = Proc_tracesyscall; 1379 ready(p); 1380 procstopwait(p, Proc_tracesyscall); 1381 break; 1382 case CMstop: 1383 procstopwait(p, Proc_stopme); 1384 break; 1385 case CMwaitstop: 1386 procstopwait(p, 0); 1387 break; 1388 case CMwired: 1389 procwired(p, atoi(cb->f[1])); 1390 break; 1391 case CMtrace: 1392 switch(cb->nf){ 1393 case 1: 1394 p->trace ^= 1; 1395 break; 1396 case 2: 1397 p->trace = atoi(cb->f[1])?1:0; 1398 break; 1399 default: 1400 error("args"); 1401 } 1402 break; 1403 /* real time */ 1404 case CMperiod: 1405 if(p->edf == nil) 1406 edfinit(p); 1407 if(e=parsetime(&time, cb->f[1])) 1408 error(e); 1409 edfstop(p); 1410 p->edf->T = time; 1411 break; 1412 case CMdeadline: 1413 if(p->edf == nil) 1414 edfinit(p); 1415 if(e=parsetime(&time, cb->f[1])) 1416 error(e); 1417 edfstop(p); 1418 p->edf->D = time; 1419 break; 1420 case CMcost: 1421 if(p->edf == nil) 1422 edfinit(p); 1423 if(e=parsetime(&time, cb->f[1])) 1424 error(e); 1425 edfstop(p); 1426 p->edf->C = time; 1427 break; 1428 case CMsporadic: 1429 if(p->edf == nil) 1430 edfinit(p); 1431 p->edf->flags |= Sporadic; 1432 break; 1433 case CMdeadlinenotes: 1434 if(p->edf == nil) 1435 edfinit(p); 1436 p->edf->flags |= Sendnotes; 1437 break; 1438 case CMadmit: 1439 if(p->edf == 0) 1440 error("edf params"); 1441 if(e = edfadmit(p)) 1442 error(e); 1443 break; 1444 case CMextra: 1445 if(p->edf == nil) 1446 edfinit(p); 1447 p->edf->flags |= Extratime; 1448 break; 1449 case CMexpel: 1450 if(p->edf) 1451 edfstop(p); 1452 break; 1453 } 1454 1455 poperror(); 1456 free(cb); 1457 } 1458 1459 int 1460 procstopped(void *a) 1461 { 1462 Proc *p = a; 1463 return p->state == Stopped; 1464 } 1465 1466 int 1467 procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 1468 { 1469 KMap *k; 1470 Pte *pte; 1471 Page *pg; 1472 Segment *s; 1473 ulong soff, l; 1474 char *a = va, *b; 1475 1476 for(;;) { 1477 s = seg(p, offset, 1); 1478 if(s == 0) 1479 error(Ebadarg); 1480 1481 if(offset+n >= s->top) 1482 n = s->top-offset; 1483 1484 if(!read && (s->type&SG_TYPE) == SG_TEXT) 1485 s = txt2data(p, s); 1486 1487 s->steal++; 1488 soff = offset-s->base; 1489 if(waserror()) { 1490 s->steal--; 1491 nexterror(); 1492 } 1493 if(fixfault(s, offset, read, 0) == 0) 1494 break; 1495 poperror(); 1496 s->steal--; 1497 } 1498 poperror(); 1499 pte = s->map[soff/PTEMAPMEM]; 1500 if(pte == 0) 1501 panic("procctlmemio"); 1502 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 1503 if(pagedout(pg)) 1504 panic("procctlmemio1"); 1505 1506 l = BY2PG - (offset&(BY2PG-1)); 1507 if(n > l) 1508 n = l; 1509 1510 k = kmap(pg); 1511 if(waserror()) { 1512 s->steal--; 1513 kunmap(k); 1514 nexterror(); 1515 } 1516 b = (char*)VA(k); 1517 b += offset&(BY2PG-1); 1518 if(read == 1) 1519 memmove(a, b, n); /* This can fault */ 1520 else 1521 memmove(b, a, n); 1522 kunmap(k); 1523 poperror(); 1524 1525 /* Ensure the process sees text page changes */ 1526 if(s->flushme) 1527 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 1528 1529 s->steal--; 1530 1531 if(read == 0) 1532 p->newtlb = 1; 1533 1534 return n; 1535 } 1536 1537 Segment* 1538 txt2data(Proc *p, Segment *s) 1539 { 1540 int i; 1541 Segment *ps; 1542 1543 ps = newseg(SG_DATA, s->base, s->size); 1544 ps->image = s->image; 1545 incref(ps->image); 1546 ps->fstart = s->fstart; 1547 ps->flen = s->flen; 1548 ps->flushme = 1; 1549 1550 qlock(&p->seglock); 1551 for(i = 0; i < NSEG; i++) 1552 if(p->seg[i] == s) 1553 break; 1554 if(p->seg[i] != s) 1555 panic("segment gone"); 1556 1557 qunlock(&s->lk); 1558 putseg(s); 1559 qlock(&ps->lk); 1560 p->seg[i] = ps; 1561 qunlock(&p->seglock); 1562 1563 return ps; 1564 } 1565 1566 Segment* 1567 data2txt(Segment *s) 1568 { 1569 Segment *ps; 1570 1571 ps = newseg(SG_TEXT, s->base, s->size); 1572 ps->image = s->image; 1573 incref(ps->image); 1574 ps->fstart = s->fstart; 1575 ps->flen = s->flen; 1576 ps->flushme = 1; 1577 1578 return ps; 1579 } 1580