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