1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include "ureg.h" 8 9 enum 10 { 11 Qdir, 12 Qargs, 13 Qctl, 14 Qfd, 15 Qfpregs, 16 Qkregs, 17 Qmem, 18 Qnote, 19 Qnoteid, 20 Qnotepg, 21 Qns, 22 Qproc, 23 Qregs, 24 Qsegment, 25 Qstatus, 26 Qtext, 27 Qwait, 28 Qprofile, 29 }; 30 31 enum 32 { 33 CMclose, 34 CMclosefiles, 35 CMfixedpri, 36 CMhang, 37 CMkill, 38 CMnohang, 39 CMnoswap, 40 CMpri, 41 CMprivate, 42 CMprofile, 43 CMstart, 44 CMstartstop, 45 CMstop, 46 CMwaitstop, 47 CMwired, 48 }; 49 50 #define STATSIZE (2*KNAMELEN+12+9*12) 51 /* 52 * Status, fd, and ns are left fully readable (0444) because of their use in debugging, 53 * particularly on shared servers. 54 * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 55 */ 56 Dirtab procdir[] = 57 { 58 "args", {Qargs}, 0, 0440, 59 "ctl", {Qctl}, 0, 0000, 60 "fd", {Qfd}, 0, 0444, 61 "fpregs", {Qfpregs}, sizeof(FPsave), 0000, 62 "kregs", {Qkregs}, sizeof(Ureg), 0400, 63 "mem", {Qmem}, 0, 0000, 64 "note", {Qnote}, 0, 0000, 65 "noteid", {Qnoteid}, 0, 0664, 66 "notepg", {Qnotepg}, 0, 0000, 67 "ns", {Qns}, 0, 0444, 68 "proc", {Qproc}, 0, 0400, 69 "regs", {Qregs}, sizeof(Ureg), 0000, 70 "segment", {Qsegment}, 0, 0444, 71 "status", {Qstatus}, STATSIZE, 0444, 72 "text", {Qtext}, 0, 0000, 73 "wait", {Qwait}, 0, 0400, 74 "profile", {Qprofile}, 0, 0400, 75 }; 76 77 static 78 Cmdtab proccmd[] = { 79 CMclose, "close", 2, 80 CMclosefiles, "closefiles", 1, 81 CMfixedpri, "fixedpri", 2, 82 CMhang, "hang", 1, 83 CMnohang, "nohang", 1, 84 CMnoswap, "noswap", 1, 85 CMkill, "kill", 1, 86 CMpri, "pri", 2, 87 CMprivate, "private", 1, 88 CMprofile, "profile", 1, 89 CMstart, "start", 1, 90 CMstartstop, "startstop", 1, 91 CMstop, "stop", 1, 92 CMwaitstop, "waitstop", 1, 93 CMwired, "wired", 2, 94 }; 95 96 /* Segment type from portdat.h */ 97 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", }; 98 99 /* 100 * Qids are, in path: 101 * 4 bits of file type (qids above) 102 * 23 bits of process slot number + 1 103 * in vers, 104 * 32 bits of pid, for consistency checking 105 * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid. 106 */ 107 #define QSHIFT 5 /* location in qid of proc slot # */ 108 109 #define QID(q) ((((ulong)(q).path)&0x0000001F)>>0) 110 #define SLOT(q) (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1) 111 #define PID(q) ((q).vers) 112 #define NOTEID(q) ((q).vers) 113 114 void procctlreq(Proc*, char*, int); 115 int procctlmemio(Proc*, ulong, int, void*, int); 116 Chan* proctext(Chan*, Proc*); 117 Segment* txt2data(Proc*, Segment*); 118 int procstopped(void*); 119 void mntscan(Mntwalk*, Proc*); 120 121 static int 122 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) 123 { 124 Qid qid; 125 Proc *p; 126 char *ename; 127 Segment *q; 128 ulong pid, path, perm, len; 129 130 if(s == DEVDOTDOT){ 131 mkqid(&qid, Qdir, 0, QTDIR); 132 devdir(c, qid, "#p", 0, eve, 0555, dp); 133 return 1; 134 } 135 136 if(c->qid.path == Qdir){ 137 if(name != nil){ 138 /* ignore s and use name to find pid */ 139 pid = strtol(name, &ename, 10); 140 if(pid==0 || ename[0]!='\0') 141 return -1; 142 s = procindex(pid); 143 if(s < 0) 144 return -1; 145 }else 146 if(s >= conf.nproc) 147 return -1; 148 p = proctab(s); 149 pid = p->pid; 150 if(pid == 0) 151 return 0; 152 sprint(up->genbuf, "%lud", pid); 153 /* 154 * String comparison is done in devwalk so name must match its formatted pid 155 */ 156 if(name != nil && strcmp(name, up->genbuf) != 0) 157 return -1; 158 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR); 159 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp); 160 return 1; 161 } 162 if(s >= nelem(procdir)) 163 return -1; 164 if(tab) 165 panic("procgen"); 166 167 tab = &procdir[s]; 168 path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */ 169 170 p = proctab(SLOT(c->qid)); 171 perm = tab->perm; 172 if(perm == 0) 173 perm = p->procmode; 174 else /* just copy read bits */ 175 perm |= p->procmode & 0444; 176 177 len = tab->length; 178 switch(QID(c->qid)) { 179 case Qwait: 180 len = p->nwait; /* incorrect size, but >0 means there's something to read */ 181 break; 182 case Qprofile: 183 q = p->seg[TSEG]; 184 if(q && q->profile) { 185 len = (q->top-q->base)>>LRESPROF; 186 len *= sizeof(*q->profile); 187 } 188 break; 189 } 190 191 mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); 192 devdir(c, qid, tab->name, len, p->user, perm, dp); 193 return 1; 194 } 195 196 static void 197 procinit(void) 198 { 199 if(conf.nproc >= (1<<(16-QSHIFT))-1) 200 print("warning: too many procs for devproc\n"); 201 } 202 203 static Chan* 204 procattach(char *spec) 205 { 206 return devattach('p', spec); 207 } 208 209 static Walkqid* 210 procwalk(Chan *c, Chan *nc, char **name, int nname) 211 { 212 return devwalk(c, nc, name, nname, 0, 0, procgen); 213 } 214 215 static int 216 procstat(Chan *c, uchar *db, int n) 217 { 218 return devstat(c, db, n, 0, 0, procgen); 219 } 220 221 /* 222 * none can't read or write state on other 223 * processes. This is to contain access of 224 * servers running as none should they be 225 * subverted by, for example, a stack attack. 226 */ 227 static void 228 nonone(Proc *p) 229 { 230 if(p == up) 231 return; 232 if(strcmp(up->user, "none") != 0) 233 return; 234 if(iseve()) 235 return; 236 error(Eperm); 237 } 238 239 static Chan* 240 procopen(Chan *c, int omode) 241 { 242 Proc *p; 243 Pgrp *pg; 244 Chan *tc; 245 int pid; 246 247 if(c->qid.type & QTDIR) 248 return devopen(c, omode, 0, 0, procgen); 249 250 p = proctab(SLOT(c->qid)); 251 qlock(&p->debug); 252 if(waserror()){ 253 qunlock(&p->debug); 254 nexterror(); 255 } 256 pid = PID(c->qid); 257 if(p->pid != pid) 258 error(Eprocdied); 259 260 omode = openmode(omode); 261 262 switch(QID(c->qid)){ 263 case Qtext: 264 if(omode != OREAD) 265 error(Eperm); 266 tc = proctext(c, p); 267 tc->offset = 0; 268 qunlock(&p->debug); 269 poperror(); 270 return tc; 271 272 case Qproc: 273 case Qkregs: 274 case Qsegment: 275 case Qprofile: 276 case Qfd: 277 if(omode != OREAD) 278 error(Eperm); 279 break; 280 281 case Qmem: 282 case Qnote: 283 case Qctl: 284 if(p->privatemem) 285 error(Eperm); 286 /* fall through */ 287 case Qargs: 288 case Qnoteid: 289 case Qstatus: 290 case Qwait: 291 case Qregs: 292 case Qfpregs: 293 nonone(p); 294 break; 295 296 case Qns: 297 if(omode != OREAD) 298 error(Eperm); 299 c->aux = malloc(sizeof(Mntwalk)); 300 break; 301 302 case Qnotepg: 303 nonone(p); 304 pg = p->pgrp; 305 if(pg == nil) 306 error(Eprocdied); 307 if(omode!=OWRITE || pg->pgrpid == 1) 308 error(Eperm); 309 c->pgrpid.path = pg->pgrpid+1; 310 c->pgrpid.vers = p->noteid; 311 break; 312 313 default: 314 pprint("procopen %lux\n", c->qid); 315 error(Egreg); 316 } 317 318 /* Affix pid to qid */ 319 if(p->state != Dead) 320 c->qid.vers = p->pid; 321 322 /* make sure the process slot didn't get reallocated while we were playing */ 323 coherence(); 324 if(p->pid != pid) 325 error(Eprocdied); 326 327 tc = devopen(c, omode, 0, 0, procgen); 328 qunlock(&p->debug); 329 poperror(); 330 331 return tc; 332 } 333 334 static int 335 procwstat(Chan *c, uchar *db, int n) 336 { 337 Proc *p; 338 Dir *d; 339 340 if(c->qid.type&QTDIR) 341 error(Eperm); 342 343 p = proctab(SLOT(c->qid)); 344 nonone(p); 345 d = nil; 346 if(waserror()){ 347 free(d); 348 qunlock(&p->debug); 349 nexterror(); 350 } 351 qlock(&p->debug); 352 353 if(p->pid != PID(c->qid)) 354 error(Eprocdied); 355 356 if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0) 357 error(Eperm); 358 359 d = smalloc(sizeof(Dir)+n); 360 n = convM2D(db, n, &d[0], (char*)&d[1]); 361 if(n == 0) 362 error(Eshortstat); 363 if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){ 364 if(strcmp(up->user, eve) != 0) 365 error(Eperm); 366 else 367 kstrdup(&p->user, d->uid); 368 } 369 if(d->mode != ~0UL) 370 p->procmode = d->mode&0777; 371 372 poperror(); 373 free(d); 374 qunlock(&p->debug); 375 return n; 376 } 377 378 379 static long 380 procoffset(long offset, char *va, int *np) 381 { 382 if(offset > 0) { 383 offset -= *np; 384 if(offset < 0) { 385 memmove(va, va+*np+offset, -offset); 386 *np = -offset; 387 } 388 else 389 *np = 0; 390 } 391 return offset; 392 } 393 394 static int 395 procqidwidth(Chan *c) 396 { 397 char buf[32]; 398 399 return sprint(buf, "%lud", c->qid.vers); 400 } 401 402 int 403 procfdprint(Chan *c, int fd, int w, char *s, int ns) 404 { 405 int n; 406 407 if(w == 0) 408 w = procqidwidth(c); 409 n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", 410 fd, 411 &"r w rw"[(c->mode&3)<<1], 412 devtab[c->type]->dc, c->dev, 413 c->qid.path, w, c->qid.vers, c->qid.type, 414 c->iounit, c->offset, c->name->s); 415 return n; 416 } 417 418 static int 419 procfds(Proc *p, char *va, int count, long offset) 420 { 421 Fgrp *f; 422 Chan *c; 423 char buf[256]; 424 int n, i, w, ww; 425 char *a; 426 427 /* print to buf to avoid holding fgrp lock while writing to user space */ 428 if(count > sizeof buf) 429 count = sizeof buf; 430 a = buf; 431 432 qlock(&p->debug); 433 f = p->fgrp; 434 if(f == nil){ 435 qunlock(&p->debug); 436 return 0; 437 } 438 lock(f); 439 if(waserror()){ 440 unlock(f); 441 qunlock(&p->debug); 442 nexterror(); 443 } 444 445 n = readstr(0, a, count, p->dot->name->s); 446 n += snprint(a+n, count-n, "\n"); 447 offset = procoffset(offset, a, &n); 448 /* compute width of qid.path */ 449 w = 0; 450 for(i = 0; i <= f->maxfd; i++) { 451 c = f->fd[i]; 452 if(c == nil) 453 continue; 454 ww = procqidwidth(c); 455 if(ww > w) 456 w = ww; 457 } 458 for(i = 0; i <= f->maxfd; i++) { 459 c = f->fd[i]; 460 if(c == nil) 461 continue; 462 n += procfdprint(c, i, w, a+n, count-n); 463 offset = procoffset(offset, a, &n); 464 } 465 unlock(f); 466 qunlock(&p->debug); 467 poperror(); 468 469 /* copy result to user space, now that locks are released */ 470 memmove(va, buf, n); 471 472 return n; 473 } 474 475 static void 476 procclose(Chan * c) 477 { 478 if(QID(c->qid) == Qns && c->aux != 0) 479 free(c->aux); 480 } 481 482 static void 483 int2flag(int flag, char *s) 484 { 485 if(flag == 0){ 486 *s = '\0'; 487 return; 488 } 489 *s++ = '-'; 490 if(flag & MAFTER) 491 *s++ = 'a'; 492 if(flag & MBEFORE) 493 *s++ = 'b'; 494 if(flag & MCREATE) 495 *s++ = 'c'; 496 if(flag & MCACHE) 497 *s++ = 'C'; 498 *s = '\0'; 499 } 500 501 static int 502 procargs(Proc *p, char *buf, int nbuf) 503 { 504 int j, k, m; 505 char *a; 506 int n; 507 508 a = p->args; 509 n = p->nargs; 510 for(j = 0; j < nbuf - 1; j += m){ 511 if(n == 0) 512 break; 513 if(j != 0) 514 buf[j++] = ' '; 515 m = snprint(buf+j, nbuf-j, "%q", a); 516 k = strlen(a) + 1; 517 a += k; 518 n -= k; 519 } 520 return j; 521 } 522 523 static long 524 procread(Chan *c, void *va, long n, vlong off) 525 { 526 int m; 527 long l; 528 Proc *p; 529 Waitq *wq; 530 Ureg kur; 531 uchar *rptr; 532 Mntwalk *mw; 533 Segment *sg, *s; 534 char *a = va, *sps; 535 int i, j, rsize, pid; 536 char statbuf[NSEG*32], *srv, flag[10]; 537 ulong offset = off; 538 539 if(c->qid.type & QTDIR) 540 return devdirread(c, a, n, 0, 0, procgen); 541 542 p = proctab(SLOT(c->qid)); 543 if(p->pid != PID(c->qid)) 544 error(Eprocdied); 545 546 switch(QID(c->qid)){ 547 case Qargs: 548 j = procargs(p, p->genbuf, sizeof p->genbuf); 549 if(offset >= j) 550 return 0; 551 if(offset+n > j) 552 n = j-offset; 553 memmove(a, &p->genbuf[offset], n); 554 return n; 555 556 case Qmem: 557 if(offset < KZERO 558 || (offset >= USTKTOP-USTKSIZE && offset < USTKTOP)) 559 return procctlmemio(p, offset, n, va, 1); 560 561 if(!iseve()) 562 error(Eperm); 563 564 /* validate kernel addresses */ 565 if(offset < (ulong)end) { 566 if(offset+n > (ulong)end) 567 n = (ulong)end - offset; 568 memmove(a, (char*)offset, n); 569 return n; 570 } 571 /* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */ 572 if(offset >= conf.base0 && offset < conf.npage0){ 573 if(offset+n > conf.npage0) 574 n = conf.npage0 - offset; 575 memmove(a, (char*)offset, n); 576 return n; 577 } 578 if(offset >= conf.base1 && offset < conf.npage1){ 579 if(offset+n > conf.npage1) 580 n = conf.npage1 - offset; 581 memmove(a, (char*)offset, n); 582 return n; 583 } 584 error(Ebadarg); 585 586 case Qprofile: 587 s = p->seg[TSEG]; 588 if(s == 0 || s->profile == 0) 589 error("profile is off"); 590 i = (s->top-s->base)>>LRESPROF; 591 i *= sizeof(*s->profile); 592 if(offset >= i) 593 return 0; 594 if(offset+n > i) 595 n = i - offset; 596 memmove(a, ((char*)s->profile)+offset, n); 597 return n; 598 599 case Qnote: 600 qlock(&p->debug); 601 if(waserror()){ 602 qunlock(&p->debug); 603 nexterror(); 604 } 605 if(p->pid != PID(c->qid)) 606 error(Eprocdied); 607 if(n < 1) /* must accept at least the '\0' */ 608 error(Etoosmall); 609 if(p->nnote == 0) 610 n = 0; 611 else { 612 m = strlen(p->note[0].msg) + 1; 613 if(m > n) 614 m = n; 615 memmove(va, p->note[0].msg, m); 616 ((char*)va)[m-1] = '\0'; 617 p->nnote--; 618 memmove(p->note, p->note+1, p->nnote*sizeof(Note)); 619 n = m; 620 } 621 if(p->nnote == 0) 622 p->notepending = 0; 623 poperror(); 624 qunlock(&p->debug); 625 return n; 626 627 case Qproc: 628 if(offset >= sizeof(Proc)) 629 return 0; 630 if(offset+n > sizeof(Proc)) 631 n = sizeof(Proc) - offset; 632 memmove(a, ((char*)p)+offset, n); 633 return n; 634 635 case Qregs: 636 rptr = (uchar*)p->dbgreg; 637 rsize = sizeof(Ureg); 638 goto regread; 639 640 case Qkregs: 641 memset(&kur, 0, sizeof(Ureg)); 642 setkernur(&kur, p); 643 rptr = (uchar*)&kur; 644 rsize = sizeof(Ureg); 645 goto regread; 646 647 case Qfpregs: 648 rptr = (uchar*)&p->fpsave; 649 rsize = sizeof(FPsave); 650 regread: 651 if(rptr == 0) 652 error(Enoreg); 653 if(offset >= rsize) 654 return 0; 655 if(offset+n > rsize) 656 n = rsize - offset; 657 memmove(a, rptr+offset, n); 658 return n; 659 660 case Qstatus: 661 if(offset >= STATSIZE) 662 return 0; 663 if(offset+n > STATSIZE) 664 n = STATSIZE - offset; 665 666 sps = p->psstate; 667 if(sps == 0) 668 sps = statename[p->state]; 669 memset(statbuf, ' ', sizeof statbuf); 670 memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text)); 671 memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user)); 672 memmove(statbuf+2*KNAMELEN, sps, strlen(sps)); 673 j = 2*KNAMELEN + 12; 674 675 for(i = 0; i < 6; i++) { 676 l = p->time[i]; 677 if(i == TReal) 678 l = MACHP(0)->ticks - l; 679 l = TK2MS(l); 680 readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 681 } 682 /* ignore stack, which is mostly non-existent */ 683 l = 0; 684 for(i=1; i<NSEG; i++){ 685 s = p->seg[i]; 686 if(s) 687 l += s->top - s->base; 688 } 689 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE); 690 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE); 691 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE); 692 memmove(a, statbuf+offset, n); 693 return n; 694 695 case Qsegment: 696 j = 0; 697 for(i = 0; i < NSEG; i++) { 698 sg = p->seg[i]; 699 if(sg == 0) 700 continue; 701 j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n", 702 sname[sg->type&SG_TYPE], 703 sg->type&SG_RONLY ? 'R' : ' ', 704 sg->profile ? 'P' : ' ', 705 sg->base, sg->top, sg->ref); 706 } 707 if(offset >= j) 708 return 0; 709 if(offset+n > j) 710 n = j-offset; 711 if(n == 0 && offset == 0) 712 exhausted("segments"); 713 memmove(a, &statbuf[offset], n); 714 return n; 715 716 case Qwait: 717 if(!canqlock(&p->qwaitr)) 718 error(Einuse); 719 720 if(waserror()) { 721 qunlock(&p->qwaitr); 722 nexterror(); 723 } 724 725 lock(&p->exl); 726 if(up == p && p->nchild == 0 && p->waitq == 0) { 727 unlock(&p->exl); 728 error(Enochild); 729 } 730 pid = p->pid; 731 while(p->waitq == 0) { 732 unlock(&p->exl); 733 sleep(&p->waitr, haswaitq, p); 734 if(p->pid != pid) 735 error(Eprocdied); 736 lock(&p->exl); 737 } 738 wq = p->waitq; 739 p->waitq = wq->next; 740 p->nwait--; 741 unlock(&p->exl); 742 743 qunlock(&p->qwaitr); 744 poperror(); 745 n = snprint(a, n, "%d %lud %lud %lud %q", 746 wq->w.pid, 747 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal], 748 wq->w.msg); 749 free(wq); 750 return n; 751 752 case Qns: 753 qlock(&p->debug); 754 if(waserror()){ 755 qunlock(&p->debug); 756 nexterror(); 757 } 758 if(p->pgrp == nil || p->pid != PID(c->qid)) 759 error(Eprocdied); 760 mw = c->aux; 761 if(mw->cddone){ 762 qunlock(&p->debug); 763 poperror(); 764 return 0; 765 } 766 mntscan(mw, p); 767 if(mw->mh == 0){ 768 mw->cddone = 1; 769 i = snprint(a, n, "cd %s\n", p->dot->name->s); 770 qunlock(&p->debug); 771 poperror(); 772 return i; 773 } 774 int2flag(mw->cm->mflag, flag); 775 if(strcmp(mw->cm->to->name->s, "#M") == 0){ 776 srv = srvname(mw->cm->to->mchan); 777 i = snprint(a, n, "mount %s %s %s %s\n", flag, 778 srv==nil? mw->cm->to->mchan->name->s : srv, 779 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : ""); 780 free(srv); 781 }else 782 i = snprint(a, n, "bind %s %s %s\n", flag, 783 mw->cm->to->name->s, mw->mh->from->name->s); 784 qunlock(&p->debug); 785 poperror(); 786 return i; 787 788 case Qnoteid: 789 return readnum(offset, va, n, p->noteid, NUMSIZE); 790 case Qfd: 791 return procfds(p, va, n, offset); 792 } 793 error(Egreg); 794 return 0; /* not reached */ 795 } 796 797 void 798 mntscan(Mntwalk *mw, Proc *p) 799 { 800 Pgrp *pg; 801 Mount *t; 802 Mhead *f; 803 int nxt, i; 804 ulong last, bestmid; 805 806 pg = p->pgrp; 807 rlock(&pg->ns); 808 809 nxt = 0; 810 bestmid = ~0; 811 812 last = 0; 813 if(mw->mh) 814 last = mw->cm->mountid; 815 816 for(i = 0; i < MNTHASH; i++) { 817 for(f = pg->mnthash[i]; f; f = f->hash) { 818 for(t = f->mount; t; t = t->next) { 819 if(mw->mh == 0 || 820 (t->mountid > last && t->mountid < bestmid)) { 821 mw->cm = t; 822 mw->mh = f; 823 bestmid = mw->cm->mountid; 824 nxt = 1; 825 } 826 } 827 } 828 } 829 if(nxt == 0) 830 mw->mh = 0; 831 832 runlock(&pg->ns); 833 } 834 835 static long 836 procwrite(Chan *c, void *va, long n, vlong off) 837 { 838 int id; 839 Proc *p, *t, *et; 840 char *a, buf[ERRMAX]; 841 ulong offset = off; 842 843 a = va; 844 if(c->qid.type & QTDIR) 845 error(Eisdir); 846 847 p = proctab(SLOT(c->qid)); 848 849 /* Use the remembered noteid in the channel rather 850 * than the process pgrpid 851 */ 852 if(QID(c->qid) == Qnotepg) { 853 pgrpnote(NOTEID(c->pgrpid), va, n, NUser); 854 return n; 855 } 856 857 qlock(&p->debug); 858 if(waserror()){ 859 qunlock(&p->debug); 860 nexterror(); 861 } 862 if(p->pid != PID(c->qid)) 863 error(Eprocdied); 864 865 switch(QID(c->qid)){ 866 case Qmem: 867 if(p->state != Stopped) 868 error(Ebadctl); 869 870 n = procctlmemio(p, offset, n, va, 0); 871 break; 872 873 case Qregs: 874 if(offset >= sizeof(Ureg)) 875 return 0; 876 if(offset+n > sizeof(Ureg)) 877 n = sizeof(Ureg) - offset; 878 if(p->dbgreg == 0) 879 error(Enoreg); 880 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n); 881 break; 882 883 case Qfpregs: 884 if(offset >= sizeof(FPsave)) 885 return 0; 886 if(offset+n > sizeof(FPsave)) 887 n = sizeof(FPsave) - offset; 888 memmove((uchar*)&p->fpsave+offset, va, n); 889 break; 890 891 case Qctl: 892 procctlreq(p, va, n); 893 break; 894 895 case Qnote: 896 if(p->kp) 897 error(Eperm); 898 if(n >= ERRMAX-1) 899 error(Etoobig); 900 memmove(buf, va, n); 901 buf[n] = 0; 902 if(!postnote(p, 0, buf, NUser)) 903 error("note not posted"); 904 break; 905 case Qnoteid: 906 id = atoi(a); 907 if(id == p->pid) { 908 p->noteid = id; 909 break; 910 } 911 t = proctab(0); 912 for(et = t+conf.nproc; t < et; t++) { 913 if(id == t->noteid) { 914 if(strcmp(p->user, t->user) != 0) 915 error(Eperm); 916 p->noteid = id; 917 break; 918 } 919 } 920 if(p->noteid != id) 921 error(Ebadarg); 922 break; 923 default: 924 pprint("unknown qid in procwrite\n"); 925 error(Egreg); 926 } 927 poperror(); 928 qunlock(&p->debug); 929 return n; 930 } 931 932 Dev procdevtab = { 933 'p', 934 "proc", 935 936 devreset, 937 procinit, 938 devshutdown, 939 procattach, 940 procwalk, 941 procstat, 942 procopen, 943 devcreate, 944 procclose, 945 procread, 946 devbread, 947 procwrite, 948 devbwrite, 949 devremove, 950 procwstat, 951 }; 952 953 Chan* 954 proctext(Chan *c, Proc *p) 955 { 956 Chan *tc; 957 Image *i; 958 Segment *s; 959 960 s = p->seg[TSEG]; 961 if(s == 0) 962 error(Enonexist); 963 if(p->state==Dead) 964 error(Eprocdied); 965 966 lock(s); 967 i = s->image; 968 if(i == 0) { 969 unlock(s); 970 error(Eprocdied); 971 } 972 unlock(s); 973 974 lock(i); 975 if(waserror()) { 976 unlock(i); 977 nexterror(); 978 } 979 980 tc = i->c; 981 if(tc == 0) 982 error(Eprocdied); 983 984 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { 985 cclose(tc); 986 error(Eprocdied); 987 } 988 989 if(p->pid != PID(c->qid)) 990 error(Eprocdied); 991 992 unlock(i); 993 poperror(); 994 995 return tc; 996 } 997 998 void 999 procstopwait(Proc *p, int ctl) 1000 { 1001 int pid; 1002 1003 if(p->pdbg) 1004 error(Einuse); 1005 if(procstopped(p) || p->state == Broken) 1006 return; 1007 1008 if(ctl != 0) 1009 p->procctl = ctl; 1010 p->pdbg = up; 1011 pid = p->pid; 1012 qunlock(&p->debug); 1013 up->psstate = "Stopwait"; 1014 if(waserror()) { 1015 p->pdbg = 0; 1016 qlock(&p->debug); 1017 nexterror(); 1018 } 1019 sleep(&up->sleep, procstopped, p); 1020 poperror(); 1021 qlock(&p->debug); 1022 if(p->pid != pid) 1023 error(Eprocdied); 1024 } 1025 1026 static void 1027 procctlcloseone(Proc *p, Fgrp *f, int fd) 1028 { 1029 Chan *c; 1030 1031 c = f->fd[fd]; 1032 if(c == nil) 1033 return; 1034 f->fd[fd] = nil; 1035 unlock(f); 1036 qunlock(&p->debug); 1037 cclose(c); 1038 qlock(&p->debug); 1039 lock(f); 1040 } 1041 1042 void 1043 procctlclosefiles(Proc *p, int all, int fd) 1044 { 1045 int i; 1046 Fgrp *f; 1047 1048 f = p->fgrp; 1049 if(f == nil) 1050 error(Eprocdied); 1051 1052 lock(f); 1053 f->ref++; 1054 if(all) 1055 for(i = 0; i < f->maxfd; i++) 1056 procctlcloseone(p, f, i); 1057 else 1058 procctlcloseone(p, f, fd); 1059 unlock(f); 1060 closefgrp(f); 1061 } 1062 1063 void 1064 procctlreq(Proc *p, char *va, int n) 1065 { 1066 Segment *s; 1067 int i, npc; 1068 Cmdbuf *cb; 1069 Cmdtab *ct; 1070 1071 if(p->kp) /* no ctl requests to kprocs */ 1072 error(Eperm); 1073 1074 cb = parsecmd(va, n); 1075 if(waserror()){ 1076 free(cb); 1077 nexterror(); 1078 } 1079 1080 ct = lookupcmd(cb, proccmd, nelem(proccmd)); 1081 1082 switch(ct->index){ 1083 case CMclose: 1084 procctlclosefiles(p, 0, atoi(cb->f[1])); 1085 break; 1086 case CMclosefiles: 1087 procctlclosefiles(p, 1, 0); 1088 break; 1089 case CMfixedpri: 1090 i = atoi(cb->f[1]); 1091 if(i < 0) 1092 i = 0; 1093 if(i >= Nrq) 1094 i = Nrq - 1; 1095 if(i > p->basepri && !iseve()) 1096 error(Eperm); 1097 p->basepri = i; 1098 p->fixedpri = 1; 1099 break; 1100 case CMhang: 1101 p->hang = 1; 1102 break; 1103 case CMkill: 1104 switch(p->state) { 1105 case Broken: 1106 unbreak(p); 1107 break; 1108 case Stopped: 1109 postnote(p, 0, "sys: killed", NExit); 1110 p->procctl = Proc_exitme; 1111 ready(p); 1112 break; 1113 default: 1114 postnote(p, 0, "sys: killed", NExit); 1115 p->procctl = Proc_exitme; 1116 } 1117 break; 1118 case CMnohang: 1119 p->hang = 0; 1120 break; 1121 case CMnoswap: 1122 p->noswap = 1; 1123 break; 1124 case CMpri: 1125 i = atoi(cb->f[1]); 1126 if(i < 0) 1127 i = 0; 1128 if(i >= Nrq) 1129 i = Nrq - 1; 1130 if(i > p->basepri && !iseve()) 1131 error(Eperm); 1132 p->basepri = i; 1133 p->fixedpri = 0; 1134 break; 1135 case CMprivate: 1136 p->privatemem = 1; 1137 break; 1138 case CMprofile: 1139 s = p->seg[TSEG]; 1140 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT) 1141 error(Ebadctl); 1142 if(s->profile != 0) 1143 free(s->profile); 1144 npc = (s->top-s->base)>>LRESPROF; 1145 s->profile = malloc(npc*sizeof(*s->profile)); 1146 if(s->profile == 0) 1147 error(Enomem); 1148 break; 1149 case CMstart: 1150 if(p->state != Stopped) 1151 error(Ebadctl); 1152 ready(p); 1153 break; 1154 case CMstartstop: 1155 if(p->state != Stopped) 1156 error(Ebadctl); 1157 p->procctl = Proc_traceme; 1158 ready(p); 1159 procstopwait(p, Proc_traceme); 1160 break; 1161 case CMstop: 1162 procstopwait(p, Proc_stopme); 1163 break; 1164 case CMwaitstop: 1165 procstopwait(p, 0); 1166 break; 1167 case CMwired: 1168 procwired(p, atoi(cb->f[1])); 1169 break; 1170 } 1171 1172 poperror(); 1173 free(cb); 1174 } 1175 1176 int 1177 procstopped(void *a) 1178 { 1179 Proc *p = a; 1180 return p->state == Stopped; 1181 } 1182 1183 int 1184 procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 1185 { 1186 KMap *k; 1187 Pte *pte; 1188 Page *pg; 1189 Segment *s; 1190 ulong soff, l; 1191 char *a = va, *b; 1192 1193 for(;;) { 1194 s = seg(p, offset, 1); 1195 if(s == 0) 1196 error(Ebadarg); 1197 1198 if(offset+n >= s->top) 1199 n = s->top-offset; 1200 1201 if(!read && (s->type&SG_TYPE) == SG_TEXT) 1202 s = txt2data(p, s); 1203 1204 s->steal++; 1205 soff = offset-s->base; 1206 if(waserror()) { 1207 s->steal--; 1208 nexterror(); 1209 } 1210 if(fixfault(s, offset, read, 0) == 0) 1211 break; 1212 poperror(); 1213 s->steal--; 1214 } 1215 poperror(); 1216 pte = s->map[soff/PTEMAPMEM]; 1217 if(pte == 0) 1218 panic("procctlmemio"); 1219 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 1220 if(pagedout(pg)) 1221 panic("procctlmemio1"); 1222 1223 l = BY2PG - (offset&(BY2PG-1)); 1224 if(n > l) 1225 n = l; 1226 1227 k = kmap(pg); 1228 if(waserror()) { 1229 s->steal--; 1230 kunmap(k); 1231 nexterror(); 1232 } 1233 b = (char*)VA(k); 1234 b += offset&(BY2PG-1); 1235 if(read == 1) 1236 memmove(a, b, n); /* This can fault */ 1237 else 1238 memmove(b, a, n); 1239 kunmap(k); 1240 poperror(); 1241 1242 /* Ensure the process sees text page changes */ 1243 if(s->flushme) 1244 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 1245 1246 s->steal--; 1247 1248 if(read == 0) 1249 p->newtlb = 1; 1250 1251 return n; 1252 } 1253 1254 Segment* 1255 txt2data(Proc *p, Segment *s) 1256 { 1257 int i; 1258 Segment *ps; 1259 1260 ps = newseg(SG_DATA, s->base, s->size); 1261 ps->image = s->image; 1262 incref(ps->image); 1263 ps->fstart = s->fstart; 1264 ps->flen = s->flen; 1265 ps->flushme = 1; 1266 1267 qlock(&p->seglock); 1268 for(i = 0; i < NSEG; i++) 1269 if(p->seg[i] == s) 1270 break; 1271 if(p->seg[i] != s) 1272 panic("segment gone"); 1273 1274 qunlock(&s->lk); 1275 putseg(s); 1276 qlock(&ps->lk); 1277 p->seg[i] = ps; 1278 qunlock(&p->seglock); 1279 1280 return ps; 1281 } 1282 1283 Segment* 1284 data2txt(Segment *s) 1285 { 1286 Segment *ps; 1287 1288 ps = newseg(SG_TEXT, s->base, s->size); 1289 ps->image = s->image; 1290 incref(ps->image); 1291 ps->fstart = s->fstart; 1292 ps->flen = s->flen; 1293 ps->flushme = 1; 1294 1295 return ps; 1296 } 1297