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