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