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