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 char *a, flag[10], *sps, *srv, statbuf[NSEG*32]; 675 int i, j, m, navail, ne, pid, rsize; 676 long l; 677 uchar *rptr; 678 ulong offset; 679 Confmem *cm; 680 Mntwalk *mw; 681 Proc *p; 682 Segment *sg, *s; 683 Ureg kur; 684 Waitq *wq; 685 686 a = va; 687 offset = off; 688 689 if(c->qid.type & QTDIR) 690 return devdirread(c, a, n, 0, 0, procgen); 691 692 if(QID(c->qid) == Qtrace){ 693 if(!eventsavailable(nil)) 694 return 0; 695 696 rptr = (uchar*)va; 697 navail = tproduced - tconsumed; 698 if(navail > n / sizeof(Traceevent)) 699 navail = n / sizeof(Traceevent); 700 while(navail > 0) { 701 ne = ((tconsumed & Emask) + navail > Nevents)? 702 Nevents - (tconsumed & Emask): navail; 703 memmove(rptr, &tevents[tconsumed & Emask], 704 ne * sizeof(Traceevent)); 705 706 tconsumed += ne; 707 rptr += ne * sizeof(Traceevent); 708 navail -= ne; 709 } 710 return rptr - (uchar*)va; 711 } 712 713 p = proctab(SLOT(c->qid)); 714 if(p->pid != PID(c->qid)) 715 error(Eprocdied); 716 717 switch(QID(c->qid)){ 718 case Qargs: 719 qlock(&p->debug); 720 j = procargs(p, p->genbuf, sizeof p->genbuf); 721 qunlock(&p->debug); 722 if(offset >= j) 723 return 0; 724 if(offset+n > j) 725 n = j-offset; 726 memmove(a, &p->genbuf[offset], n); 727 return n; 728 729 case Qmem: 730 if(offset < KZERO) 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 for(i=0; i<nelem(conf.mem); i++){ 744 cm = &conf.mem[i]; 745 /* klimit-1 because klimit might be zero! */ 746 if(cm->kbase <= offset && offset <= cm->klimit-1){ 747 if(offset+n >= cm->klimit-1) 748 n = cm->klimit - offset; 749 memmove(a, (char*)offset, n); 750 return n; 751 } 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->path->s); 939 qunlock(&p->debug); 940 poperror(); 941 return i; 942 } 943 int2flag(mw->cm->mflag, flag); 944 if(strcmp(mw->cm->to->path->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->path->s : srv, 948 mw->mh->from->path->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->path->s, mw->mh->from->path->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 void (*pt)(Proc*, int, vlong); 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 p->procctl = Proc_exitme; 1324 postnote(p, 0, "sys: killed", NExit); 1325 ready(p); 1326 break; 1327 default: 1328 p->procctl = Proc_exitme; 1329 postnote(p, 0, "sys: killed", NExit); 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]) != 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])) /* time in ns */ 1409 error(e); 1410 edfstop(p); 1411 p->edf->T = time/1000; /* Edf times are in µs */ 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/1000; 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/1000; 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 case CMevent: 1455 pt = proctrace; 1456 if(up->trace && pt) 1457 pt(up, SUser, 0); 1458 break; 1459 } 1460 1461 poperror(); 1462 free(cb); 1463 } 1464 1465 int 1466 procstopped(void *a) 1467 { 1468 Proc *p = a; 1469 return p->state == Stopped; 1470 } 1471 1472 int 1473 procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 1474 { 1475 KMap *k; 1476 Pte *pte; 1477 Page *pg; 1478 Segment *s; 1479 ulong soff, l; 1480 char *a = va, *b; 1481 1482 for(;;) { 1483 s = seg(p, offset, 1); 1484 if(s == 0) 1485 error(Ebadarg); 1486 1487 if(offset+n >= s->top) 1488 n = s->top-offset; 1489 1490 if(!read && (s->type&SG_TYPE) == SG_TEXT) 1491 s = txt2data(p, s); 1492 1493 s->steal++; 1494 soff = offset-s->base; 1495 if(waserror()) { 1496 s->steal--; 1497 nexterror(); 1498 } 1499 if(fixfault(s, offset, read, 0) == 0) 1500 break; 1501 poperror(); 1502 s->steal--; 1503 } 1504 poperror(); 1505 pte = s->map[soff/PTEMAPMEM]; 1506 if(pte == 0) 1507 panic("procctlmemio"); 1508 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 1509 if(pagedout(pg)) 1510 panic("procctlmemio1"); 1511 1512 l = BY2PG - (offset&(BY2PG-1)); 1513 if(n > l) 1514 n = l; 1515 1516 k = kmap(pg); 1517 if(waserror()) { 1518 s->steal--; 1519 kunmap(k); 1520 nexterror(); 1521 } 1522 b = (char*)VA(k); 1523 b += offset&(BY2PG-1); 1524 if(read == 1) 1525 memmove(a, b, n); /* This can fault */ 1526 else 1527 memmove(b, a, n); 1528 kunmap(k); 1529 poperror(); 1530 1531 /* Ensure the process sees text page changes */ 1532 if(s->flushme) 1533 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 1534 1535 s->steal--; 1536 1537 if(read == 0) 1538 p->newtlb = 1; 1539 1540 return n; 1541 } 1542 1543 Segment* 1544 txt2data(Proc *p, Segment *s) 1545 { 1546 int i; 1547 Segment *ps; 1548 1549 ps = newseg(SG_DATA, s->base, s->size); 1550 ps->image = s->image; 1551 incref(ps->image); 1552 ps->fstart = s->fstart; 1553 ps->flen = s->flen; 1554 ps->flushme = 1; 1555 1556 qlock(&p->seglock); 1557 for(i = 0; i < NSEG; i++) 1558 if(p->seg[i] == s) 1559 break; 1560 if(p->seg[i] != s) 1561 panic("segment gone"); 1562 1563 qunlock(&s->lk); 1564 putseg(s); 1565 qlock(&ps->lk); 1566 p->seg[i] = ps; 1567 qunlock(&p->seglock); 1568 1569 return ps; 1570 } 1571 1572 Segment* 1573 data2txt(Segment *s) 1574 { 1575 Segment *ps; 1576 1577 ps = newseg(SG_TEXT, s->base, s->size); 1578 ps->image = s->image; 1579 incref(ps->image); 1580 ps->fstart = s->fstart; 1581 ps->flen = s->flen; 1582 ps->flushme = 1; 1583 1584 return ps; 1585 } 1586