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