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, 0660, 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 if(p->setargs){ 510 snprint(buf, nbuf, "%s [%s]", p->text, p->args); 511 return strlen(buf); 512 } 513 n = p->nargs; 514 for(j = 0; j < nbuf - 1; j += m){ 515 if(n <= 0) 516 break; 517 if(j != 0) 518 buf[j++] = ' '; 519 m = snprint(buf+j, nbuf-j, "%q", a); 520 k = strlen(a) + 1; 521 a += k; 522 n -= k; 523 } 524 return j; 525 } 526 527 static long 528 procread(Chan *c, void *va, long n, vlong off) 529 { 530 int m; 531 long l; 532 Proc *p; 533 Waitq *wq; 534 Ureg kur; 535 uchar *rptr; 536 Mntwalk *mw; 537 Segment *sg, *s; 538 char *a = va, *sps; 539 int i, j, rsize, pid; 540 char statbuf[NSEG*32], *srv, flag[10]; 541 ulong offset = off; 542 543 if(c->qid.type & QTDIR) 544 return devdirread(c, a, n, 0, 0, procgen); 545 546 p = proctab(SLOT(c->qid)); 547 if(p->pid != PID(c->qid)) 548 error(Eprocdied); 549 550 switch(QID(c->qid)){ 551 case Qargs: 552 qlock(&p->debug); 553 j = procargs(p, p->genbuf, sizeof p->genbuf); 554 qunlock(&p->debug); 555 if(offset >= j) 556 return 0; 557 if(offset+n > j) 558 n = j-offset; 559 memmove(a, &p->genbuf[offset], n); 560 return n; 561 562 case Qmem: 563 if(offset < KZERO 564 || (offset >= USTKTOP-USTKSIZE && offset < USTKTOP)) 565 return procctlmemio(p, offset, n, va, 1); 566 567 if(!iseve()) 568 error(Eperm); 569 570 /* validate kernel addresses */ 571 if(offset < (ulong)end) { 572 if(offset+n > (ulong)end) 573 n = (ulong)end - offset; 574 memmove(a, (char*)offset, n); 575 return n; 576 } 577 /* conf.base* and conf.npage* are set by xinit to refer to kernel allocation, not user pages */ 578 if(offset >= conf.base0 && offset < conf.npage0){ 579 if(offset+n > conf.npage0) 580 n = conf.npage0 - offset; 581 memmove(a, (char*)offset, n); 582 return n; 583 } 584 if(offset >= conf.base1 && offset < conf.npage1){ 585 if(offset+n > conf.npage1) 586 n = conf.npage1 - offset; 587 memmove(a, (char*)offset, n); 588 return n; 589 } 590 error(Ebadarg); 591 592 case Qprofile: 593 s = p->seg[TSEG]; 594 if(s == 0 || s->profile == 0) 595 error("profile is off"); 596 i = (s->top-s->base)>>LRESPROF; 597 i *= sizeof(*s->profile); 598 if(offset >= i) 599 return 0; 600 if(offset+n > i) 601 n = i - offset; 602 memmove(a, ((char*)s->profile)+offset, n); 603 return n; 604 605 case Qnote: 606 qlock(&p->debug); 607 if(waserror()){ 608 qunlock(&p->debug); 609 nexterror(); 610 } 611 if(p->pid != PID(c->qid)) 612 error(Eprocdied); 613 if(n < 1) /* must accept at least the '\0' */ 614 error(Etoosmall); 615 if(p->nnote == 0) 616 n = 0; 617 else { 618 m = strlen(p->note[0].msg) + 1; 619 if(m > n) 620 m = n; 621 memmove(va, p->note[0].msg, m); 622 ((char*)va)[m-1] = '\0'; 623 p->nnote--; 624 memmove(p->note, p->note+1, p->nnote*sizeof(Note)); 625 n = m; 626 } 627 if(p->nnote == 0) 628 p->notepending = 0; 629 poperror(); 630 qunlock(&p->debug); 631 return n; 632 633 case Qproc: 634 if(offset >= sizeof(Proc)) 635 return 0; 636 if(offset+n > sizeof(Proc)) 637 n = sizeof(Proc) - offset; 638 memmove(a, ((char*)p)+offset, n); 639 return n; 640 641 case Qregs: 642 rptr = (uchar*)p->dbgreg; 643 rsize = sizeof(Ureg); 644 goto regread; 645 646 case Qkregs: 647 memset(&kur, 0, sizeof(Ureg)); 648 setkernur(&kur, p); 649 rptr = (uchar*)&kur; 650 rsize = sizeof(Ureg); 651 goto regread; 652 653 case Qfpregs: 654 rptr = (uchar*)&p->fpsave; 655 rsize = sizeof(FPsave); 656 regread: 657 if(rptr == 0) 658 error(Enoreg); 659 if(offset >= rsize) 660 return 0; 661 if(offset+n > rsize) 662 n = rsize - offset; 663 memmove(a, rptr+offset, n); 664 return n; 665 666 case Qstatus: 667 if(offset >= STATSIZE) 668 return 0; 669 if(offset+n > STATSIZE) 670 n = STATSIZE - offset; 671 672 sps = p->psstate; 673 if(sps == 0) 674 sps = statename[p->state]; 675 memset(statbuf, ' ', sizeof statbuf); 676 memmove(statbuf+0*KNAMELEN, p->text, strlen(p->text)); 677 memmove(statbuf+1*KNAMELEN, p->user, strlen(p->user)); 678 memmove(statbuf+2*KNAMELEN, sps, strlen(sps)); 679 j = 2*KNAMELEN + 12; 680 681 for(i = 0; i < 6; i++) { 682 l = p->time[i]; 683 if(i == TReal) 684 l = MACHP(0)->ticks - l; 685 l = TK2MS(l); 686 readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE); 687 } 688 /* ignore stack, which is mostly non-existent */ 689 l = 0; 690 for(i=1; i<NSEG; i++){ 691 s = p->seg[i]; 692 if(s) 693 l += s->top - s->base; 694 } 695 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, l>>10, NUMSIZE); 696 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE); 697 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE); 698 memmove(a, statbuf+offset, n); 699 return n; 700 701 case Qsegment: 702 j = 0; 703 for(i = 0; i < NSEG; i++) { 704 sg = p->seg[i]; 705 if(sg == 0) 706 continue; 707 j += sprint(statbuf+j, "%-6s %c%c %.8lux %.8lux %4ld\n", 708 sname[sg->type&SG_TYPE], 709 sg->type&SG_RONLY ? 'R' : ' ', 710 sg->profile ? 'P' : ' ', 711 sg->base, sg->top, sg->ref); 712 } 713 if(offset >= j) 714 return 0; 715 if(offset+n > j) 716 n = j-offset; 717 if(n == 0 && offset == 0) 718 exhausted("segments"); 719 memmove(a, &statbuf[offset], n); 720 return n; 721 722 case Qwait: 723 if(!canqlock(&p->qwaitr)) 724 error(Einuse); 725 726 if(waserror()) { 727 qunlock(&p->qwaitr); 728 nexterror(); 729 } 730 731 lock(&p->exl); 732 if(up == p && p->nchild == 0 && p->waitq == 0) { 733 unlock(&p->exl); 734 error(Enochild); 735 } 736 pid = p->pid; 737 while(p->waitq == 0) { 738 unlock(&p->exl); 739 sleep(&p->waitr, haswaitq, p); 740 if(p->pid != pid) 741 error(Eprocdied); 742 lock(&p->exl); 743 } 744 wq = p->waitq; 745 p->waitq = wq->next; 746 p->nwait--; 747 unlock(&p->exl); 748 749 qunlock(&p->qwaitr); 750 poperror(); 751 n = snprint(a, n, "%d %lud %lud %lud %q", 752 wq->w.pid, 753 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal], 754 wq->w.msg); 755 free(wq); 756 return n; 757 758 case Qns: 759 qlock(&p->debug); 760 if(waserror()){ 761 qunlock(&p->debug); 762 nexterror(); 763 } 764 if(p->pgrp == nil || p->pid != PID(c->qid)) 765 error(Eprocdied); 766 mw = c->aux; 767 if(mw->cddone){ 768 qunlock(&p->debug); 769 poperror(); 770 return 0; 771 } 772 mntscan(mw, p); 773 if(mw->mh == 0){ 774 mw->cddone = 1; 775 i = snprint(a, n, "cd %s\n", p->dot->name->s); 776 qunlock(&p->debug); 777 poperror(); 778 return i; 779 } 780 int2flag(mw->cm->mflag, flag); 781 if(strcmp(mw->cm->to->name->s, "#M") == 0){ 782 srv = srvname(mw->cm->to->mchan); 783 i = snprint(a, n, "mount %s %s %s %s\n", flag, 784 srv==nil? mw->cm->to->mchan->name->s : srv, 785 mw->mh->from->name->s, mw->cm->spec? mw->cm->spec : ""); 786 free(srv); 787 }else 788 i = snprint(a, n, "bind %s %s %s\n", flag, 789 mw->cm->to->name->s, mw->mh->from->name->s); 790 qunlock(&p->debug); 791 poperror(); 792 return i; 793 794 case Qnoteid: 795 return readnum(offset, va, n, p->noteid, NUMSIZE); 796 case Qfd: 797 return procfds(p, va, n, offset); 798 } 799 error(Egreg); 800 return 0; /* not reached */ 801 } 802 803 void 804 mntscan(Mntwalk *mw, Proc *p) 805 { 806 Pgrp *pg; 807 Mount *t; 808 Mhead *f; 809 int nxt, i; 810 ulong last, bestmid; 811 812 pg = p->pgrp; 813 rlock(&pg->ns); 814 815 nxt = 0; 816 bestmid = ~0; 817 818 last = 0; 819 if(mw->mh) 820 last = mw->cm->mountid; 821 822 for(i = 0; i < MNTHASH; i++) { 823 for(f = pg->mnthash[i]; f; f = f->hash) { 824 for(t = f->mount; t; t = t->next) { 825 if(mw->mh == 0 || 826 (t->mountid > last && t->mountid < bestmid)) { 827 mw->cm = t; 828 mw->mh = f; 829 bestmid = mw->cm->mountid; 830 nxt = 1; 831 } 832 } 833 } 834 } 835 if(nxt == 0) 836 mw->mh = 0; 837 838 runlock(&pg->ns); 839 } 840 841 static long 842 procwrite(Chan *c, void *va, long n, vlong off) 843 { 844 int id, m; 845 Proc *p, *t, *et; 846 char *a, *arg, buf[ERRMAX]; 847 ulong offset = off; 848 849 a = va; 850 if(c->qid.type & QTDIR) 851 error(Eisdir); 852 853 p = proctab(SLOT(c->qid)); 854 855 /* Use the remembered noteid in the channel rather 856 * than the process pgrpid 857 */ 858 if(QID(c->qid) == Qnotepg) { 859 pgrpnote(NOTEID(c->pgrpid), va, n, NUser); 860 return n; 861 } 862 863 qlock(&p->debug); 864 if(waserror()){ 865 qunlock(&p->debug); 866 nexterror(); 867 } 868 if(p->pid != PID(c->qid)) 869 error(Eprocdied); 870 871 switch(QID(c->qid)){ 872 case Qargs: 873 if(n == 0) 874 error(Eshort); 875 if(n >= ERRMAX) 876 error(Etoobig); 877 arg = malloc(n+1); 878 if(arg == nil) 879 error(Enomem); 880 memmove(arg, va, n); 881 m = n; 882 if(arg[m-1] != 0) 883 arg[m++] = 0; 884 free(p->args); 885 p->nargs = m; 886 p->args = arg; 887 p->setargs = 1; 888 break; 889 890 case Qmem: 891 if(p->state != Stopped) 892 error(Ebadctl); 893 894 n = procctlmemio(p, offset, n, va, 0); 895 break; 896 897 case Qregs: 898 if(offset >= sizeof(Ureg)) 899 return 0; 900 if(offset+n > sizeof(Ureg)) 901 n = sizeof(Ureg) - offset; 902 if(p->dbgreg == 0) 903 error(Enoreg); 904 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n); 905 break; 906 907 case Qfpregs: 908 if(offset >= sizeof(FPsave)) 909 return 0; 910 if(offset+n > sizeof(FPsave)) 911 n = sizeof(FPsave) - offset; 912 memmove((uchar*)&p->fpsave+offset, va, n); 913 break; 914 915 case Qctl: 916 procctlreq(p, va, n); 917 break; 918 919 case Qnote: 920 if(p->kp) 921 error(Eperm); 922 if(n >= ERRMAX-1) 923 error(Etoobig); 924 memmove(buf, va, n); 925 buf[n] = 0; 926 if(!postnote(p, 0, buf, NUser)) 927 error("note not posted"); 928 break; 929 case Qnoteid: 930 id = atoi(a); 931 if(id == p->pid) { 932 p->noteid = id; 933 break; 934 } 935 t = proctab(0); 936 for(et = t+conf.nproc; t < et; t++) { 937 if(id == t->noteid) { 938 if(strcmp(p->user, t->user) != 0) 939 error(Eperm); 940 p->noteid = id; 941 break; 942 } 943 } 944 if(p->noteid != id) 945 error(Ebadarg); 946 break; 947 default: 948 pprint("unknown qid in procwrite\n"); 949 error(Egreg); 950 } 951 poperror(); 952 qunlock(&p->debug); 953 return n; 954 } 955 956 Dev procdevtab = { 957 'p', 958 "proc", 959 960 devreset, 961 procinit, 962 devshutdown, 963 procattach, 964 procwalk, 965 procstat, 966 procopen, 967 devcreate, 968 procclose, 969 procread, 970 devbread, 971 procwrite, 972 devbwrite, 973 devremove, 974 procwstat, 975 }; 976 977 Chan* 978 proctext(Chan *c, Proc *p) 979 { 980 Chan *tc; 981 Image *i; 982 Segment *s; 983 984 s = p->seg[TSEG]; 985 if(s == 0) 986 error(Enonexist); 987 if(p->state==Dead) 988 error(Eprocdied); 989 990 lock(s); 991 i = s->image; 992 if(i == 0) { 993 unlock(s); 994 error(Eprocdied); 995 } 996 unlock(s); 997 998 lock(i); 999 if(waserror()) { 1000 unlock(i); 1001 nexterror(); 1002 } 1003 1004 tc = i->c; 1005 if(tc == 0) 1006 error(Eprocdied); 1007 1008 if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) { 1009 cclose(tc); 1010 error(Eprocdied); 1011 } 1012 1013 if(p->pid != PID(c->qid)) 1014 error(Eprocdied); 1015 1016 unlock(i); 1017 poperror(); 1018 1019 return tc; 1020 } 1021 1022 void 1023 procstopwait(Proc *p, int ctl) 1024 { 1025 int pid; 1026 1027 if(p->pdbg) 1028 error(Einuse); 1029 if(procstopped(p) || p->state == Broken) 1030 return; 1031 1032 if(ctl != 0) 1033 p->procctl = ctl; 1034 p->pdbg = up; 1035 pid = p->pid; 1036 qunlock(&p->debug); 1037 up->psstate = "Stopwait"; 1038 if(waserror()) { 1039 p->pdbg = 0; 1040 qlock(&p->debug); 1041 nexterror(); 1042 } 1043 sleep(&up->sleep, procstopped, p); 1044 poperror(); 1045 qlock(&p->debug); 1046 if(p->pid != pid) 1047 error(Eprocdied); 1048 } 1049 1050 static void 1051 procctlcloseone(Proc *p, Fgrp *f, int fd) 1052 { 1053 Chan *c; 1054 1055 c = f->fd[fd]; 1056 if(c == nil) 1057 return; 1058 f->fd[fd] = nil; 1059 unlock(f); 1060 qunlock(&p->debug); 1061 cclose(c); 1062 qlock(&p->debug); 1063 lock(f); 1064 } 1065 1066 void 1067 procctlclosefiles(Proc *p, int all, int fd) 1068 { 1069 int i; 1070 Fgrp *f; 1071 1072 f = p->fgrp; 1073 if(f == nil) 1074 error(Eprocdied); 1075 1076 lock(f); 1077 f->ref++; 1078 if(all) 1079 for(i = 0; i < f->maxfd; i++) 1080 procctlcloseone(p, f, i); 1081 else 1082 procctlcloseone(p, f, fd); 1083 unlock(f); 1084 closefgrp(f); 1085 } 1086 1087 void 1088 procctlreq(Proc *p, char *va, int n) 1089 { 1090 Segment *s; 1091 int i, npc; 1092 Cmdbuf *cb; 1093 Cmdtab *ct; 1094 1095 if(p->kp) /* no ctl requests to kprocs */ 1096 error(Eperm); 1097 1098 cb = parsecmd(va, n); 1099 if(waserror()){ 1100 free(cb); 1101 nexterror(); 1102 } 1103 1104 ct = lookupcmd(cb, proccmd, nelem(proccmd)); 1105 1106 switch(ct->index){ 1107 case CMclose: 1108 procctlclosefiles(p, 0, atoi(cb->f[1])); 1109 break; 1110 case CMclosefiles: 1111 procctlclosefiles(p, 1, 0); 1112 break; 1113 case CMfixedpri: 1114 i = atoi(cb->f[1]); 1115 if(i < 0) 1116 i = 0; 1117 if(i >= Nrq) 1118 i = Nrq - 1; 1119 if(i > p->basepri && !iseve()) 1120 error(Eperm); 1121 p->basepri = i; 1122 p->fixedpri = 1; 1123 break; 1124 case CMhang: 1125 p->hang = 1; 1126 break; 1127 case CMkill: 1128 switch(p->state) { 1129 case Broken: 1130 unbreak(p); 1131 break; 1132 case Stopped: 1133 postnote(p, 0, "sys: killed", NExit); 1134 p->procctl = Proc_exitme; 1135 ready(p); 1136 break; 1137 default: 1138 postnote(p, 0, "sys: killed", NExit); 1139 p->procctl = Proc_exitme; 1140 } 1141 break; 1142 case CMnohang: 1143 p->hang = 0; 1144 break; 1145 case CMnoswap: 1146 p->noswap = 1; 1147 break; 1148 case CMpri: 1149 i = atoi(cb->f[1]); 1150 if(i < 0) 1151 i = 0; 1152 if(i >= Nrq) 1153 i = Nrq - 1; 1154 if(i > p->basepri && !iseve()) 1155 error(Eperm); 1156 p->basepri = i; 1157 p->fixedpri = 0; 1158 break; 1159 case CMprivate: 1160 p->privatemem = 1; 1161 break; 1162 case CMprofile: 1163 s = p->seg[TSEG]; 1164 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT) 1165 error(Ebadctl); 1166 if(s->profile != 0) 1167 free(s->profile); 1168 npc = (s->top-s->base)>>LRESPROF; 1169 s->profile = malloc(npc*sizeof(*s->profile)); 1170 if(s->profile == 0) 1171 error(Enomem); 1172 break; 1173 case CMstart: 1174 if(p->state != Stopped) 1175 error(Ebadctl); 1176 ready(p); 1177 break; 1178 case CMstartstop: 1179 if(p->state != Stopped) 1180 error(Ebadctl); 1181 p->procctl = Proc_traceme; 1182 ready(p); 1183 procstopwait(p, Proc_traceme); 1184 break; 1185 case CMstop: 1186 procstopwait(p, Proc_stopme); 1187 break; 1188 case CMwaitstop: 1189 procstopwait(p, 0); 1190 break; 1191 case CMwired: 1192 procwired(p, atoi(cb->f[1])); 1193 break; 1194 } 1195 1196 poperror(); 1197 free(cb); 1198 } 1199 1200 int 1201 procstopped(void *a) 1202 { 1203 Proc *p = a; 1204 return p->state == Stopped; 1205 } 1206 1207 int 1208 procctlmemio(Proc *p, ulong offset, int n, void *va, int read) 1209 { 1210 KMap *k; 1211 Pte *pte; 1212 Page *pg; 1213 Segment *s; 1214 ulong soff, l; 1215 char *a = va, *b; 1216 1217 for(;;) { 1218 s = seg(p, offset, 1); 1219 if(s == 0) 1220 error(Ebadarg); 1221 1222 if(offset+n >= s->top) 1223 n = s->top-offset; 1224 1225 if(!read && (s->type&SG_TYPE) == SG_TEXT) 1226 s = txt2data(p, s); 1227 1228 s->steal++; 1229 soff = offset-s->base; 1230 if(waserror()) { 1231 s->steal--; 1232 nexterror(); 1233 } 1234 if(fixfault(s, offset, read, 0) == 0) 1235 break; 1236 poperror(); 1237 s->steal--; 1238 } 1239 poperror(); 1240 pte = s->map[soff/PTEMAPMEM]; 1241 if(pte == 0) 1242 panic("procctlmemio"); 1243 pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 1244 if(pagedout(pg)) 1245 panic("procctlmemio1"); 1246 1247 l = BY2PG - (offset&(BY2PG-1)); 1248 if(n > l) 1249 n = l; 1250 1251 k = kmap(pg); 1252 if(waserror()) { 1253 s->steal--; 1254 kunmap(k); 1255 nexterror(); 1256 } 1257 b = (char*)VA(k); 1258 b += offset&(BY2PG-1); 1259 if(read == 1) 1260 memmove(a, b, n); /* This can fault */ 1261 else 1262 memmove(b, a, n); 1263 kunmap(k); 1264 poperror(); 1265 1266 /* Ensure the process sees text page changes */ 1267 if(s->flushme) 1268 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl)); 1269 1270 s->steal--; 1271 1272 if(read == 0) 1273 p->newtlb = 1; 1274 1275 return n; 1276 } 1277 1278 Segment* 1279 txt2data(Proc *p, Segment *s) 1280 { 1281 int i; 1282 Segment *ps; 1283 1284 ps = newseg(SG_DATA, s->base, s->size); 1285 ps->image = s->image; 1286 incref(ps->image); 1287 ps->fstart = s->fstart; 1288 ps->flen = s->flen; 1289 ps->flushme = 1; 1290 1291 qlock(&p->seglock); 1292 for(i = 0; i < NSEG; i++) 1293 if(p->seg[i] == s) 1294 break; 1295 if(p->seg[i] != s) 1296 panic("segment gone"); 1297 1298 qunlock(&s->lk); 1299 putseg(s); 1300 qlock(&ps->lk); 1301 p->seg[i] = ps; 1302 qunlock(&p->seglock); 1303 1304 return ps; 1305 } 1306 1307 Segment* 1308 data2txt(Segment *s) 1309 { 1310 Segment *ps; 1311 1312 ps = newseg(SG_TEXT, s->base, s->size); 1313 ps->image = s->image; 1314 incref(ps->image); 1315 ps->fstart = s->fstart; 1316 ps->flen = s->flen; 1317 ps->flushme = 1; 1318 1319 return ps; 1320 } 1321