devproc.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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 }