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