2016-12-11 01:19:51 +01:00
|
|
|
/*
|
|
|
|
* This file is part of Jehanne.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2015-2016 Giacomo Tesio <giacomo@tesio.it>
|
|
|
|
*
|
|
|
|
* Jehanne is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, version 2 of the License.
|
|
|
|
*
|
|
|
|
* Jehanne is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with Jehanne. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2016-11-25 17:18:40 +01:00
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "../port/error.h"
|
|
|
|
|
|
|
|
#include <trace.h>
|
|
|
|
#include "ureg.h"
|
|
|
|
|
2016-12-15 22:42:01 +01:00
|
|
|
extern long write_working_dir(Proc* p, void *va, long n, int64_t off);
|
|
|
|
extern long read_working_dir(Proc* p, void *va, long n, int64_t off);
|
|
|
|
|
|
|
|
/* We can have up to 32 files in proc/n sice we dedicate 5 bits in Qid
|
|
|
|
* to it (see QSHIFT)
|
|
|
|
*/
|
2016-11-25 17:18:40 +01:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
Qdir,
|
|
|
|
Qtrace,
|
|
|
|
Qargs,
|
|
|
|
Qctl,
|
|
|
|
Qfd,
|
|
|
|
Qfpregs,
|
|
|
|
Qkregs,
|
|
|
|
Qmem,
|
|
|
|
Qnote,
|
|
|
|
Qnoteid,
|
|
|
|
Qnotepg,
|
|
|
|
Qns,
|
|
|
|
Qproc,
|
|
|
|
Qregs,
|
|
|
|
Qsegment,
|
|
|
|
Qstatus,
|
|
|
|
Qtext,
|
|
|
|
Qwait,
|
|
|
|
Qprofile,
|
|
|
|
Qsyscall,
|
2016-12-15 22:42:01 +01:00
|
|
|
Qwdir,
|
2016-11-25 17:18:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
CMclose,
|
|
|
|
CMclosefiles,
|
|
|
|
CMfixedpri,
|
|
|
|
CMhang,
|
|
|
|
CMkill,
|
|
|
|
CMnohang,
|
|
|
|
CMnoswap,
|
|
|
|
CMpri,
|
|
|
|
CMprivate,
|
|
|
|
CMprofile,
|
|
|
|
CMstart,
|
|
|
|
CMstartstop,
|
|
|
|
CMstartsyscall,
|
|
|
|
CMstop,
|
|
|
|
CMwaitstop,
|
|
|
|
CMwired,
|
|
|
|
CMtrace,
|
|
|
|
};
|
|
|
|
|
|
|
|
enum{
|
|
|
|
Nevents = 0x4000,
|
|
|
|
Emask = Nevents - 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
#define STATSIZE (2*KNAMELEN+NUMSIZE+9*NUMSIZE + 1)
|
2016-12-15 22:42:01 +01:00
|
|
|
/* In Plan 9 status, fd, and ns were left fully readable (0444)
|
|
|
|
* because of their use in debugging, particularly on shared servers.
|
|
|
|
*
|
|
|
|
* In Jehanne the process owner and the host owner can read
|
|
|
|
* status and fd, but not others (0440).
|
|
|
|
* TODO: allow per process stats and permissions.
|
2016-11-25 17:18:40 +01:00
|
|
|
*/
|
|
|
|
Dirtab procdir[] =
|
|
|
|
{
|
|
|
|
"args", {Qargs}, 0, 0660,
|
|
|
|
"ctl", {Qctl}, 0, 0000,
|
2016-12-15 22:42:01 +01:00
|
|
|
"fd", {Qfd}, 0, 0440,
|
2016-11-25 17:18:40 +01:00
|
|
|
"fpregs", {Qfpregs}, 0, 0000,
|
|
|
|
"kregs", {Qkregs}, sizeof(Ureg), 0400,
|
|
|
|
"mem", {Qmem}, 0, 0000,
|
|
|
|
"note", {Qnote}, 0, 0000,
|
|
|
|
"noteid", {Qnoteid}, 0, 0664,
|
|
|
|
"notepg", {Qnotepg}, 0, 0000,
|
2016-12-15 22:42:01 +01:00
|
|
|
"ns", {Qns}, 0, 0440,
|
2016-11-25 17:18:40 +01:00
|
|
|
"proc", {Qproc}, 0, 0400,
|
|
|
|
"regs", {Qregs}, sizeof(Ureg), 0000,
|
2016-12-11 01:19:51 +01:00
|
|
|
"segment", {Qsegment}, 0, 0444,
|
2016-11-25 17:18:40 +01:00
|
|
|
"status", {Qstatus}, STATSIZE, 0444,
|
|
|
|
"text", {Qtext}, 0, 0000,
|
|
|
|
"wait", {Qwait}, 0, 0400,
|
|
|
|
"syscall", {Qsyscall}, 0, 0400,
|
2016-12-15 22:42:01 +01:00
|
|
|
"wdir", {Qwdir}, 0, 0640,
|
2016-11-25 17:18:40 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static
|
|
|
|
Cmdtab proccmd[] = {
|
|
|
|
CMclose, "close", 2,
|
|
|
|
CMclosefiles, "closefiles", 1,
|
|
|
|
CMfixedpri, "fixedpri", 2,
|
|
|
|
CMhang, "hang", 1,
|
|
|
|
CMnohang, "nohang", 1,
|
|
|
|
CMnoswap, "noswap", 1,
|
|
|
|
CMkill, "kill", 1,
|
|
|
|
CMpri, "pri", 2,
|
|
|
|
CMprivate, "private", 1,
|
|
|
|
CMstart, "start", 1,
|
|
|
|
CMstartstop, "startstop", 1,
|
|
|
|
CMstartsyscall, "startsyscall", 1,
|
|
|
|
CMstop, "stop", 1,
|
|
|
|
CMwaitstop, "waitstop", 1,
|
|
|
|
CMwired, "wired", 2,
|
|
|
|
CMtrace, "trace", 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Qids are, in path:
|
2016-12-15 22:42:01 +01:00
|
|
|
* 5 bits of file type (qids above)
|
2016-11-25 17:18:40 +01:00
|
|
|
* 23 bits of process slot number + 1
|
|
|
|
* in vers,
|
|
|
|
* 32 bits of pid, for consistency checking
|
|
|
|
* If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
|
|
|
|
*/
|
|
|
|
#define QSHIFT 5 /* location in qid of proc slot # */
|
|
|
|
|
|
|
|
#define QID(q) ((((uint32_t)(q).path)&0x0000001F)>>0)
|
|
|
|
#define SLOT(q) (((((uint32_t)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
|
|
|
|
#define PID(q) ((q).vers)
|
|
|
|
#define NOTEID(q) ((q).vers)
|
|
|
|
|
|
|
|
static void procctlreq(Proc*, char*, int);
|
|
|
|
static int procctlmemio(Proc*, uintptr_t, int, void*, int);
|
|
|
|
static Chan* proctext(Chan*, Proc*);
|
|
|
|
static int procstopped(void*);
|
|
|
|
static void mntscan(Mntwalk*, Proc*);
|
|
|
|
|
|
|
|
static Traceevent *tevents;
|
|
|
|
static Lock tlock;
|
|
|
|
static int topens;
|
|
|
|
static int tproduced, tconsumed;
|
|
|
|
|
|
|
|
static void
|
|
|
|
profclock(Ureg *ur, Timer * _1)
|
|
|
|
{
|
|
|
|
if(up == nil || up->state != Running)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procgen(Chan *c, char *name, Dirtab *tab, int _1, int s, Dir *dp)
|
|
|
|
{
|
|
|
|
Qid qid;
|
|
|
|
Proc *p;
|
|
|
|
char *ename;
|
|
|
|
int pid;
|
|
|
|
uint32_t path, perm, len;
|
|
|
|
|
|
|
|
if(s == DEVDOTDOT){
|
|
|
|
mkqid(&qid, Qdir, 0, QTDIR);
|
|
|
|
devdir(c, qid, "#p", 0, eve, 0555, dp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(c->qid.path == Qdir){
|
|
|
|
if(s == 0){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_strcpy(up->genbuf, "trace");
|
2016-11-25 17:18:40 +01:00
|
|
|
mkqid(&qid, Qtrace, -1, QTFILE);
|
|
|
|
devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(name != nil){
|
|
|
|
/* ignore s and use name to find pid */
|
2017-04-19 23:33:14 +02:00
|
|
|
pid = jehanne_strtol(name, &ename, 10);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(pid<=0 || ename[0]!='\0')
|
|
|
|
return -1;
|
|
|
|
s = psindex(pid);
|
|
|
|
if(s < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if(--s >= procalloc.nproc)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if((p = psincref(s)) == nil || (pid = p->pid) == 0)
|
|
|
|
return 0;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_sprint(up->genbuf, "%d", pid);
|
2016-11-25 17:18:40 +01:00
|
|
|
/*
|
|
|
|
* String comparison is done in devwalk so
|
|
|
|
* name must match its formatted pid.
|
|
|
|
*/
|
2017-04-19 23:33:14 +02:00
|
|
|
if(name != nil && jehanne_strcmp(name, up->genbuf) != 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
return -1;
|
|
|
|
mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
|
|
|
|
devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
|
|
|
|
psdecref(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(c->qid.path == Qtrace){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_strcpy(up->genbuf, "trace");
|
2016-11-25 17:18:40 +01:00
|
|
|
mkqid(&qid, Qtrace, -1, QTFILE);
|
|
|
|
devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if(s >= nelem(procdir))
|
|
|
|
return -1;
|
|
|
|
if(tab)
|
|
|
|
panic("procgen");
|
|
|
|
|
|
|
|
tab = &procdir[s];
|
|
|
|
path = c->qid.path&~(((1<<QSHIFT)-1)); /* slot component */
|
|
|
|
|
|
|
|
if((p = psincref(SLOT(c->qid))) == nil)
|
|
|
|
return -1;
|
|
|
|
perm = tab->perm;
|
|
|
|
if(perm == 0)
|
|
|
|
perm = p->procmode;
|
|
|
|
else /* just copy read bits */
|
|
|
|
perm |= p->procmode & 0444;
|
|
|
|
|
|
|
|
len = tab->length;
|
|
|
|
switch(QID(c->qid)) {
|
|
|
|
case Qwait:
|
|
|
|
len = p->nwait; /* incorrect size, but >0 means there's something to read */
|
|
|
|
break;
|
|
|
|
}
|
2016-12-15 22:42:01 +01:00
|
|
|
switch(QID(tab->qid)){
|
|
|
|
case Qwdir:
|
|
|
|
/* file length might be relevant to the caller to
|
|
|
|
* malloc enough space in the buffer
|
|
|
|
*/
|
2017-04-19 23:33:14 +02:00
|
|
|
len = 1 + jehanne_strlen(p->dot->path->s);
|
2016-12-15 22:42:01 +01:00
|
|
|
break;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
|
|
|
|
devdir(c, qid, tab->name, len, p->user, perm, dp);
|
|
|
|
psdecref(p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_proctrace(Proc* p, int etype, int64_t ts, int64_t _1)
|
|
|
|
{
|
|
|
|
Traceevent *te;
|
|
|
|
|
|
|
|
if (p->trace == 0 || topens == 0 ||
|
|
|
|
tproduced - tconsumed >= Nevents)
|
|
|
|
return;
|
|
|
|
|
|
|
|
te = &tevents[tproduced&Emask];
|
|
|
|
te->pid = p->pid;
|
|
|
|
te->etype = (Tevent)etype;
|
|
|
|
if (ts == 0)
|
|
|
|
te->time = todget(nil);
|
|
|
|
else
|
|
|
|
te->time = ts;
|
|
|
|
tproduced++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
procinit(void)
|
|
|
|
{
|
|
|
|
if(procalloc.nproc >= (1<<(16-QSHIFT))-1)
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_print("warning: too many procs for devproc\n");
|
2016-11-25 17:18:40 +01:00
|
|
|
addclock0link((void (*)(void))profclock, 113); /* Relative prime to HZ */
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
procattach(Chan *c, Chan *ac, char *spec, int flags)
|
|
|
|
{
|
|
|
|
return devattach('p', spec);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Walkqid*
|
|
|
|
procwalk(Chan *c, Chan *nc, char **name, int nname)
|
|
|
|
{
|
|
|
|
return devwalk(c, nc, name, nname, 0, 0, procgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
procstat(Chan *c, uint8_t *db, long n)
|
|
|
|
{
|
|
|
|
return devstat(c, db, n, 0, 0, procgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* none can't read or write state on other
|
|
|
|
* processes. This is to contain access of
|
|
|
|
* servers running as none should they be
|
|
|
|
* subverted by, for example, a stack attack.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
nonone(Proc *p)
|
|
|
|
{
|
|
|
|
if(p == up)
|
|
|
|
return;
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_strcmp(up->user, "none") != 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
return;
|
|
|
|
if(isevegroup())
|
|
|
|
return;
|
|
|
|
error(Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
2016-12-01 00:09:42 +01:00
|
|
|
procopen(Chan *c, unsigned long omode)
|
2016-11-25 17:18:40 +01:00
|
|
|
{
|
|
|
|
Proc *p;
|
|
|
|
Pgrp *pg;
|
|
|
|
Chan *tc;
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
if(c->qid.type & QTDIR)
|
|
|
|
return devopen(c, omode, 0, 0, procgen);
|
|
|
|
|
|
|
|
if(QID(c->qid) == Qtrace){
|
|
|
|
if (omode != OREAD)
|
|
|
|
error(Eperm);
|
|
|
|
lock(&tlock);
|
|
|
|
if (waserror()){
|
|
|
|
unlock(&tlock);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if (topens > 0)
|
|
|
|
error("already open");
|
|
|
|
topens++;
|
|
|
|
if (tevents == nil){
|
2017-04-19 23:33:14 +02:00
|
|
|
tevents = (Traceevent*)jehanne_malloc(sizeof(Traceevent) * Nevents);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(tevents == nil)
|
|
|
|
error(Enomem);
|
|
|
|
tproduced = tconsumed = 0;
|
|
|
|
}
|
|
|
|
proctrace = _proctrace;
|
|
|
|
poperror();
|
|
|
|
unlock(&tlock);
|
|
|
|
|
|
|
|
c->mode = openmode(omode);
|
|
|
|
c->flag |= COPEN;
|
|
|
|
c->offset = 0;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p = psincref(SLOT(c->qid))) == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
pid = PID(c->qid);
|
|
|
|
if(p->pid != pid)
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
omode = openmode(omode);
|
|
|
|
|
|
|
|
switch(QID(c->qid)){
|
|
|
|
case Qtext:
|
|
|
|
if(omode != OREAD)
|
|
|
|
error(Eperm);
|
|
|
|
tc = proctext(c, p);
|
|
|
|
tc->offset = 0;
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return tc;
|
|
|
|
|
|
|
|
case Qproc:
|
|
|
|
case Qkregs:
|
|
|
|
case Qprofile:
|
|
|
|
case Qfd:
|
|
|
|
if(omode != OREAD && omode != OSTAT)
|
|
|
|
error(Eperm);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qsegment:
|
|
|
|
if(omode != OREAD && omode != OSTAT)
|
|
|
|
error(Eperm);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qnote:
|
|
|
|
if(p->privatemem)
|
|
|
|
error(Eperm);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qmem:
|
|
|
|
case Qctl:
|
|
|
|
if(p->privatemem)
|
|
|
|
error(Eperm);
|
|
|
|
nonone(p);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qargs:
|
|
|
|
case Qnoteid:
|
|
|
|
case Qstatus:
|
|
|
|
case Qwait:
|
|
|
|
case Qregs:
|
|
|
|
case Qfpregs:
|
|
|
|
nonone(p);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qsyscall:
|
|
|
|
nonone(p);
|
|
|
|
if(p->syscallq != nil)
|
|
|
|
error(Einuse);
|
|
|
|
c->aux = qopen(1024, 1, nil, nil);
|
|
|
|
p->syscallq = c->aux;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qns:
|
|
|
|
if(omode != OREAD)
|
|
|
|
error(Eperm);
|
2017-04-19 23:33:14 +02:00
|
|
|
c->aux = jehanne_malloc(sizeof(Mntwalk));
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Qnotepg:
|
|
|
|
nonone(p);
|
|
|
|
pg = p->pgrp;
|
|
|
|
if(pg == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
if(omode!=OWRITE || pg->pgrpid == 1)
|
|
|
|
error(Eperm);
|
|
|
|
c->pgrpid.path = pg->pgrpid+1;
|
|
|
|
c->pgrpid.vers = p->noteid;
|
|
|
|
break;
|
|
|
|
|
2016-12-15 22:42:01 +01:00
|
|
|
case Qwdir:
|
|
|
|
if(p == up) /* self write is always allowed */
|
|
|
|
break;
|
|
|
|
if(omode > ORDWR)
|
|
|
|
error(Eperm);
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_strcmp(up->user, p->user) != 0 /* process owner can read/write */
|
2016-12-15 22:42:01 +01:00
|
|
|
|| !iseve() /* host owner can read */
|
|
|
|
|| (omode&OWRITE) != 0)
|
|
|
|
error(Eperm);
|
|
|
|
break;
|
|
|
|
|
2016-11-25 17:18:40 +01:00
|
|
|
default:
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
pprint("procopen %#llux\n", c->qid.path);
|
|
|
|
error(Egreg);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Affix pid to qid */
|
|
|
|
if(p->state != Dead)
|
|
|
|
c->qid.vers = p->pid;
|
|
|
|
|
|
|
|
/* make sure the process slot didn't get reallocated while we were playing */
|
|
|
|
coherence();
|
|
|
|
if(p->pid != pid)
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
tc = devopen(c, omode, 0, 0, procgen);
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
|
|
|
|
return tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
procwstat(Chan *c, uint8_t *db, long n)
|
|
|
|
{
|
|
|
|
Proc *p;
|
|
|
|
Dir *d;
|
|
|
|
|
|
|
|
if(c->qid.type & QTDIR)
|
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
if(QID(c->qid) == Qtrace)
|
|
|
|
return devwstat(c, db, n);
|
|
|
|
|
|
|
|
if((p = psincref(SLOT(c->qid))) == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
nonone(p);
|
|
|
|
d = nil;
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(d);
|
2016-11-25 17:18:40 +01:00
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(p->pid != PID(c->qid))
|
|
|
|
error(Eprocdied);
|
|
|
|
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_strcmp(up->user, p->user) != 0 && jehanne_strcmp(up->user, eve) != 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
d = smalloc(sizeof(Dir)+n);
|
2017-04-19 23:33:14 +02:00
|
|
|
n = jehanne_convM2D(db, n, &d[0], (char*)&d[1]);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(n == 0)
|
|
|
|
error(Eshortstat);
|
2017-04-19 23:33:14 +02:00
|
|
|
if(!emptystr(d->uid) && jehanne_strcmp(d->uid, p->user) != 0){
|
|
|
|
if(jehanne_strcmp(up->user, eve) != 0)
|
2016-11-25 17:18:40 +01:00
|
|
|
error(Eperm);
|
|
|
|
else
|
|
|
|
kstrdup(&p->user, d->uid);
|
|
|
|
}
|
|
|
|
if(d->mode != (uint32_t)~0UL)
|
|
|
|
p->procmode = d->mode&0777;
|
|
|
|
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(d);
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
procoffset(long offset, char *va, int *np)
|
|
|
|
{
|
|
|
|
if(offset > 0) {
|
|
|
|
offset -= *np;
|
|
|
|
if(offset < 0) {
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, va+*np+offset, -offset);
|
2016-11-25 17:18:40 +01:00
|
|
|
*np = -offset;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*np = 0;
|
|
|
|
}
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procqidwidth(Chan *c)
|
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
|
2017-04-19 23:33:14 +02:00
|
|
|
return jehanne_sprint(buf, "%lud", c->qid.vers);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_procfdprint(Chan *c, int fd, int w, char *s, int ns, char * modestr)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
if(w == 0)
|
|
|
|
w = procqidwidth(c);
|
2017-04-19 23:33:14 +02:00
|
|
|
n = jehanne_snprint(s, ns, "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
|
2016-11-25 17:18:40 +01:00
|
|
|
fd,
|
|
|
|
&modestr[(c->mode&3)<<1],
|
|
|
|
c->dev->dc, c->devno,
|
|
|
|
c->qid.path, w, c->qid.vers, c->qid.type,
|
|
|
|
c->iounit, c->offset, c->path->s);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
procfdprint(Chan *c, int fd, int w, char *s, int ns)
|
|
|
|
{
|
2017-01-11 03:01:04 +01:00
|
|
|
return _procfdprint(c, fd, w, s, ns, "s r w rw");
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procfds(Proc *p, char *va, int count, long offset)
|
|
|
|
{
|
|
|
|
Fgrp *f;
|
|
|
|
Chan *c;
|
|
|
|
char buf[256];
|
|
|
|
int n, i, w, ww;
|
|
|
|
char *a, *modestr;
|
|
|
|
|
|
|
|
/* print to buf to avoid holding fgrp lock while writing to user space */
|
|
|
|
if(count > sizeof buf)
|
|
|
|
count = sizeof buf;
|
|
|
|
a = buf;
|
|
|
|
|
|
|
|
qlock(&p->debug);
|
|
|
|
f = p->fgrp;
|
|
|
|
if(f == nil){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
lock(&f->l);
|
|
|
|
if(waserror()){
|
|
|
|
unlock(&f->l);
|
|
|
|
qunlock(&p->debug);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
n = readstr(0, a, count, p->dot->path->s);
|
2017-04-19 23:33:14 +02:00
|
|
|
n += jehanne_snprint(a+n, count-n, "\n");
|
2016-11-25 17:18:40 +01:00
|
|
|
offset = procoffset(offset, a, &n);
|
|
|
|
/* compute width of qid.path */
|
|
|
|
w = 0;
|
|
|
|
for(i = 0; i <= f->maxfd; i++) {
|
|
|
|
c = f->fd[i];
|
|
|
|
if(c == nil)
|
|
|
|
continue;
|
|
|
|
ww = procqidwidth(c);
|
|
|
|
if(ww > w)
|
|
|
|
w = ww;
|
|
|
|
}
|
|
|
|
for(i = 0; i <= f->maxfd; i++) {
|
|
|
|
c = f->fd[i];
|
|
|
|
if(c == nil)
|
|
|
|
continue;
|
2017-01-11 03:01:04 +01:00
|
|
|
modestr = "s r w rw";
|
2016-11-25 17:18:40 +01:00
|
|
|
if(p->blockingfd == i){
|
|
|
|
if(p->scallnr == SysPread)
|
2017-01-11 03:01:04 +01:00
|
|
|
modestr = "s R w Rw";
|
2016-11-25 17:18:40 +01:00
|
|
|
else
|
2017-01-11 03:01:04 +01:00
|
|
|
modestr = "s r W rW";
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
n += _procfdprint(c, i, w, a+n, count-n, modestr);
|
|
|
|
offset = procoffset(offset, a, &n);
|
|
|
|
}
|
|
|
|
poperror();
|
|
|
|
unlock(&f->l);
|
|
|
|
qunlock(&p->debug);
|
|
|
|
|
|
|
|
/* copy result to user space, now that locks are released */
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, buf, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
procclose(Chan * c)
|
|
|
|
{
|
|
|
|
Proc *p;
|
|
|
|
|
|
|
|
switch(QID(c->qid)){
|
|
|
|
case Qtrace:
|
|
|
|
lock(&tlock);
|
|
|
|
if(topens > 0)
|
|
|
|
topens--;
|
|
|
|
if(topens == 0)
|
|
|
|
proctrace = nil;
|
|
|
|
unlock(&tlock);
|
|
|
|
break;
|
|
|
|
case Qns:
|
|
|
|
if(c->aux != nil)
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(c->aux);
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
case Qsyscall:
|
|
|
|
if((p = psincref(SLOT(c->qid))) != nil){
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(p->pid == PID(c->qid))
|
|
|
|
p->syscallq = nil;
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
}
|
|
|
|
if(c->aux != nil)
|
|
|
|
qfree(c->aux);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
int2flag(int flag, char *s)
|
|
|
|
{
|
|
|
|
if(flag == 0){
|
|
|
|
*s = '\0';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*s++ = '-';
|
|
|
|
if(flag & MAFTER)
|
|
|
|
*s++ = 'a';
|
|
|
|
if(flag & MBEFORE)
|
|
|
|
*s++ = 'b';
|
|
|
|
if(flag & MCREATE)
|
|
|
|
*s++ = 'c';
|
|
|
|
*s = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procargs(Proc *p, char *buf, int nbuf)
|
|
|
|
{
|
|
|
|
int i;
|
2017-08-11 01:47:15 +02:00
|
|
|
char **args, **margs, *e;
|
2016-11-25 17:18:40 +01:00
|
|
|
ProcSegment *s;
|
|
|
|
PagePointer page = 0;
|
2017-08-11 01:47:15 +02:00
|
|
|
char *pbase, *marg;
|
|
|
|
uintptr_t argaddr, ptop;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
args = p->args;
|
|
|
|
if(args == nil)
|
|
|
|
return 0;
|
|
|
|
if(p->setargs){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_snprint(buf, nbuf, "%s [%s]", p->text, args[0]);
|
|
|
|
return jehanne_strlen(buf);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
e = buf + nbuf;
|
|
|
|
|
|
|
|
/* since we did not created a copy of args on exec, we have
|
|
|
|
* to do a little black magic
|
|
|
|
*/
|
|
|
|
rlock(&p->seglock); /* enough to avoid problems since
|
|
|
|
* the stack is never shared
|
|
|
|
*/
|
|
|
|
|
|
|
|
s = p->seg[SSEG];
|
|
|
|
|
|
|
|
/* note that neither segment_page nor page_kmap increase the
|
|
|
|
* page's ref count, but this should be safe in this very specific
|
|
|
|
* case (top of the stack with seglock rlocked)
|
|
|
|
*/
|
2017-08-11 01:47:15 +02:00
|
|
|
page = segment_page(s, (uintptr_t)args);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(page == 0){
|
2017-04-19 23:33:14 +02:00
|
|
|
buf = jehanne_seprint(buf, e, "cannot print args for %s %d: stack gone", p->text, p->pid);
|
2016-11-25 17:18:40 +01:00
|
|
|
goto ArgsPrinted;
|
|
|
|
}
|
|
|
|
|
|
|
|
pbase = page_kmap(page);
|
2017-08-11 01:47:15 +02:00
|
|
|
ptop = (uintptr_t)(pbase + PGSZ);
|
2016-11-25 17:18:40 +01:00
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
margs = (char**)(pbase + (((uintptr_t)args)&(PGSZ-1)));
|
|
|
|
if(((uintptr_t)&margs[p->nargs - 1]) > ptop){
|
|
|
|
buf = jehanne_seprint(buf, e, "%s: too many arguments", p->text);
|
|
|
|
goto DoneWithMappedPage;
|
|
|
|
}
|
2016-11-25 17:18:40 +01:00
|
|
|
for(i = 0; i < p->nargs; ++i){
|
|
|
|
if(buf >= e)
|
|
|
|
break;
|
2017-08-11 01:47:15 +02:00
|
|
|
argaddr = (uintptr_t)margs[i];
|
|
|
|
if(argaddr < (uintptr_t)args || argaddr >= s->top){
|
|
|
|
buf = jehanne_seprint(buf, e, i?" %#p":"%#p", argaddr);
|
|
|
|
} else if(argaddr - (uintptr_t)args > PGSZ){
|
|
|
|
buf = jehanne_seprint(buf, e, " ...");
|
|
|
|
break;
|
2016-11-25 17:18:40 +01:00
|
|
|
} else {
|
2017-08-11 01:47:15 +02:00
|
|
|
marg = pbase + (argaddr&(PGSZ-1));
|
|
|
|
buf = jehanne_seprint(buf, e, i?" %q":"%q", marg);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
}
|
2017-08-11 01:47:15 +02:00
|
|
|
DoneWithMappedPage:
|
2016-11-25 17:18:40 +01:00
|
|
|
page_kunmap(page, &pbase);
|
|
|
|
|
|
|
|
ArgsPrinted:
|
|
|
|
runlock(&p->seglock);
|
|
|
|
return buf - (e - nbuf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
eventsavailable(void * _1)
|
|
|
|
{
|
|
|
|
return tproduced > tconsumed;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
procread(Chan *c, void *va, long n, int64_t off)
|
|
|
|
{
|
|
|
|
Proc *p;
|
|
|
|
int64_t l;
|
|
|
|
int32_t r;
|
|
|
|
Waitq *wq;
|
|
|
|
Ureg kur;
|
|
|
|
uint8_t *rptr;
|
|
|
|
Mntwalk *mw;
|
|
|
|
ProcSegment *sg, *s;
|
|
|
|
int i, j, navail, ne, pid, rsize;
|
2017-08-11 01:47:15 +02:00
|
|
|
char flag[10], *a, *sps, *srv, statbuf[NSEG*STATSIZE];
|
2016-11-25 17:18:40 +01:00
|
|
|
uintptr_t offset;
|
|
|
|
uintmem paddr, plimit, psize;
|
|
|
|
uint64_t u;
|
|
|
|
|
|
|
|
if(c->qid.type & QTDIR)
|
|
|
|
return devdirread(c, va, n, 0, 0, procgen);
|
|
|
|
|
2017-08-11 01:47:15 +02:00
|
|
|
a = va;
|
2016-11-25 17:18:40 +01:00
|
|
|
offset = off;
|
|
|
|
|
|
|
|
if(QID(c->qid) == Qtrace){
|
|
|
|
if(!eventsavailable(nil))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
rptr = va;
|
|
|
|
navail = tproduced - tconsumed;
|
|
|
|
if(navail > n / sizeof(Traceevent))
|
|
|
|
navail = n / sizeof(Traceevent);
|
|
|
|
while(navail > 0) {
|
|
|
|
if((tconsumed & Emask) + navail > Nevents)
|
|
|
|
ne = Nevents - (tconsumed & Emask);
|
|
|
|
else
|
|
|
|
ne = navail;
|
|
|
|
i = ne * sizeof(Traceevent);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(rptr, &tevents[tconsumed & Emask], i);
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
tconsumed += ne;
|
|
|
|
rptr += i;
|
|
|
|
navail -= ne;
|
|
|
|
}
|
|
|
|
return rptr - (uint8_t*)va;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p = psincref(SLOT(c->qid))) == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
if(p->pid != PID(c->qid)){
|
|
|
|
psdecref(p);
|
|
|
|
error(Eprocdied);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(QID(c->qid)){
|
|
|
|
default:
|
|
|
|
psdecref(p);
|
|
|
|
break;
|
|
|
|
case Qargs:
|
|
|
|
qlock(&p->debug);
|
|
|
|
j = procargs(p, up->genbuf, sizeof up->genbuf);
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
if(offset >= j)
|
|
|
|
return 0;
|
|
|
|
if(offset+n > j)
|
|
|
|
n = j-offset;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, &up->genbuf[offset], n);
|
2016-11-25 17:18:40 +01:00
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qsyscall:
|
|
|
|
return qread(c->aux, va, n);
|
|
|
|
|
|
|
|
case Qmem:
|
|
|
|
if(!iskaddr(offset)
|
|
|
|
|| (offset >= USTKTOP-USTKSIZE && offset < USTKTOP)){
|
|
|
|
r = procctlmemio(p, offset, n, va, 1);
|
|
|
|
psdecref(p);
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!iseve()){
|
|
|
|
psdecref(p);
|
|
|
|
error(Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validate kernel addresses */
|
|
|
|
if(offset < PTR2UINT(end)) {
|
|
|
|
if(offset+n > PTR2UINT(end))
|
|
|
|
n = PTR2UINT(end) - offset;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, UINT2PTR(offset), n);
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
paddr = PADDR(UINT2PTR(offset));
|
2017-08-11 01:47:15 +02:00
|
|
|
if(!ismapped(&rmapram, paddr, &psize)){
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(p);
|
|
|
|
error(Ebadarg);
|
|
|
|
}
|
|
|
|
plimit = paddr + psize;
|
|
|
|
/* plimit-1 because plimit might be zero (address space top) */
|
|
|
|
if(paddr+n >= plimit-1)
|
|
|
|
n = plimit - paddr;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, UINT2PTR(offset), n);
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qnote:
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if(p->pid != PID(c->qid))
|
|
|
|
error(Eprocdied);
|
|
|
|
if(n < 1) /* must accept at least the '\0' */
|
|
|
|
error(Etoosmall);
|
|
|
|
if(p->nnote == 0)
|
|
|
|
n = 0;
|
|
|
|
else {
|
2017-04-19 23:33:14 +02:00
|
|
|
i = jehanne_strlen(p->note[0].msg) + 1;
|
2016-11-25 17:18:40 +01:00
|
|
|
if(i > n)
|
|
|
|
i = n;
|
|
|
|
rptr = va;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(rptr, p->note[0].msg, i);
|
2016-11-25 17:18:40 +01:00
|
|
|
rptr[i-1] = '\0';
|
|
|
|
p->nnote--;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(p->note, p->note+1, p->nnote*sizeof(Note));
|
2016-11-25 17:18:40 +01:00
|
|
|
n = i;
|
|
|
|
}
|
|
|
|
if(p->nnote == 0)
|
|
|
|
p->notepending = 0;
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qproc:
|
|
|
|
if(offset >= sizeof(Proc)){
|
|
|
|
psdecref(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(offset+n > sizeof(Proc))
|
|
|
|
n = sizeof(Proc) - offset;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, ((char*)p)+offset, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qregs:
|
|
|
|
rptr = (uint8_t*)p->dbgreg;
|
|
|
|
rsize = sizeof(Ureg);
|
2017-08-11 01:47:15 +02:00
|
|
|
goto regread;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
case Qkregs:
|
2017-08-11 01:47:15 +02:00
|
|
|
memset(&kur, 0, sizeof(Ureg));
|
2016-11-25 17:18:40 +01:00
|
|
|
setkernur(&kur, p);
|
|
|
|
rptr = (uint8_t*)&kur;
|
|
|
|
rsize = sizeof(Ureg);
|
|
|
|
goto regread;
|
|
|
|
|
|
|
|
case Qfpregs:
|
2017-08-11 01:47:15 +02:00
|
|
|
rptr = (uint8_t*)&p->fpsave;
|
|
|
|
rsize = sizeof(FPsave);
|
|
|
|
regread:
|
|
|
|
if(rptr == nil)
|
|
|
|
error(Enoreg);
|
|
|
|
if(offset >= rsize)
|
|
|
|
return 0;
|
|
|
|
if(offset+n > rsize)
|
|
|
|
n = rsize - offset;
|
|
|
|
memmove(a, rptr+offset, n);
|
|
|
|
return n;
|
2016-11-25 17:18:40 +01:00
|
|
|
|
|
|
|
case Qstatus:
|
|
|
|
if(offset >= sizeof statbuf){
|
|
|
|
psdecref(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(offset+n > sizeof statbuf)
|
|
|
|
n = (sizeof statbuf) - offset;
|
|
|
|
|
|
|
|
sps = p->psstate;
|
|
|
|
if(sps == 0)
|
|
|
|
sps = statename[p->state];
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memset(statbuf, ' ', sizeof statbuf);
|
|
|
|
jehanne_sprint(statbuf, "%-*.*s%-*.*s%-12.11s",
|
2016-11-25 17:18:40 +01:00
|
|
|
KNAMELEN, KNAMELEN-1, p->text,
|
|
|
|
KNAMELEN, KNAMELEN-1, p->user,
|
|
|
|
sps);
|
|
|
|
j = 2*KNAMELEN + 12;
|
|
|
|
|
|
|
|
for(i = 0; i < 6; i++) {
|
|
|
|
l = p->time[i];
|
|
|
|
if(i == TReal)
|
|
|
|
l = sys->ticks - l;
|
|
|
|
l = TK2MS(l);
|
|
|
|
readnum(0, statbuf+j, NUMSIZE, l, NUMSIZE);
|
|
|
|
j += NUMSIZE;
|
|
|
|
}
|
|
|
|
/* ignore stack, which is mostly non-existent */
|
|
|
|
u = 0;
|
|
|
|
for(i=1; i<NSEG; i++){
|
|
|
|
s = p->seg[i];
|
|
|
|
if(s)
|
|
|
|
u += s->top - s->base;
|
|
|
|
}
|
|
|
|
readnum(0, statbuf+j, NUMSIZE, u>>10, NUMSIZE);
|
|
|
|
j += NUMSIZE;
|
|
|
|
readnum(0, statbuf+j, NUMSIZE, p->basepri, NUMSIZE);
|
|
|
|
j += NUMSIZE;
|
|
|
|
readnum(0, statbuf+j, NUMSIZE, p->priority, NUMSIZE);
|
|
|
|
j += NUMSIZE;
|
|
|
|
statbuf[j++] = '\n';
|
|
|
|
if(offset+n > j)
|
|
|
|
n = j-offset;
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, statbuf+offset, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qsegment:
|
|
|
|
j = 0;
|
|
|
|
for(i = 0; i < NSEG; i++) {
|
|
|
|
sg = p->seg[i];
|
|
|
|
if(sg == 0)
|
|
|
|
continue;
|
2017-04-19 23:33:14 +02:00
|
|
|
j += jehanne_sprint(statbuf+j, "%-6s %c%c %p %p %4d\n",
|
2016-11-25 17:18:40 +01:00
|
|
|
segment_name(sg),
|
|
|
|
!(sg->type&SgWrite) ? 'R' : ' ',
|
|
|
|
(sg->type&SgExecute) ? 'x' : ' ',
|
|
|
|
' ', // sg->profile ? 'P' : ' ', // here was profiling
|
|
|
|
sg->base, sg->top, sg->r.ref);
|
|
|
|
}
|
|
|
|
psdecref(p);
|
|
|
|
if(offset >= j)
|
|
|
|
return 0;
|
|
|
|
if(offset+n > j)
|
|
|
|
n = j-offset;
|
|
|
|
if(n == 0 && offset == 0)
|
|
|
|
exhausted("segments");
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, &statbuf[offset], n);
|
2016-11-25 17:18:40 +01:00
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qwait:
|
|
|
|
if(!canqlock(&p->qwaitr)){
|
|
|
|
psdecref(p);
|
|
|
|
error(Einuse);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(waserror()) {
|
|
|
|
qunlock(&p->qwaitr);
|
|
|
|
psdecref(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
lock(&p->exl);
|
|
|
|
if(up == p && p->nchild == 0 && p->waitq == 0) {
|
|
|
|
unlock(&p->exl);
|
|
|
|
error(Enochild);
|
|
|
|
}
|
|
|
|
pid = p->pid;
|
|
|
|
while(p->waitq == 0) {
|
|
|
|
unlock(&p->exl);
|
|
|
|
sleep(&p->waitr, haswaitq, p);
|
|
|
|
if(p->pid != pid)
|
|
|
|
error(Eprocdied);
|
|
|
|
lock(&p->exl);
|
|
|
|
}
|
|
|
|
wq = p->waitq;
|
|
|
|
p->waitq = wq->next;
|
|
|
|
p->nwait--;
|
|
|
|
unlock(&p->exl);
|
|
|
|
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->qwaitr);
|
|
|
|
psdecref(p);
|
2017-04-19 23:33:14 +02:00
|
|
|
n = jehanne_snprint(va, n, "%d %lud %lud %lud %q",
|
2016-11-25 17:18:40 +01:00
|
|
|
wq->w.pid,
|
|
|
|
wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
|
|
|
|
wq->w.msg);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(wq);
|
2016-11-25 17:18:40 +01:00
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qns:
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if(p->pgrp == nil || p->pid != PID(c->qid))
|
|
|
|
error(Eprocdied);
|
|
|
|
mw = c->aux;
|
|
|
|
if(mw->cddone){
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
mntscan(mw, p);
|
|
|
|
if(mw->mh == 0){
|
|
|
|
mw->cddone = 1;
|
2017-04-19 23:33:14 +02:00
|
|
|
i = jehanne_snprint(va, n, "cd %s\n", p->dot->path->s);
|
2016-11-25 17:18:40 +01:00
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
int2flag(mw->cm->mflag, flag);
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_strcmp(mw->cm->to->path->s, "#9") == 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
srv = srvname(mw->cm->to->mchan);
|
2017-04-19 23:33:14 +02:00
|
|
|
i = jehanne_snprint(va, n, "mount %s %s %s %s\n", flag,
|
2016-11-25 17:18:40 +01:00
|
|
|
srv==nil? mw->cm->to->mchan->path->s : srv,
|
|
|
|
mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(srv);
|
2016-11-25 17:18:40 +01:00
|
|
|
}else
|
2017-04-19 23:33:14 +02:00
|
|
|
i = jehanne_snprint(va, n, "bind %s %s %s\n", flag,
|
2016-11-25 17:18:40 +01:00
|
|
|
mw->cm->to->path->s, mw->mh->from->path->s);
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return i;
|
|
|
|
|
|
|
|
case Qnoteid:
|
|
|
|
r = readnum(offset, va, n, p->noteid, NUMSIZE);
|
|
|
|
psdecref(p);
|
|
|
|
return r;
|
|
|
|
case Qfd:
|
|
|
|
r = procfds(p, va, n, offset);
|
|
|
|
psdecref(p);
|
|
|
|
return r;
|
2016-12-15 22:42:01 +01:00
|
|
|
case Qwdir:
|
|
|
|
r = read_working_dir(p, va, n, off);
|
|
|
|
psdecref(p);
|
|
|
|
return r;
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
error(Egreg);
|
|
|
|
return 0; /* not reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mntscan(Mntwalk *mw, Proc *p)
|
|
|
|
{
|
|
|
|
Pgrp *pg;
|
|
|
|
Mount *t;
|
|
|
|
Mhead *f;
|
|
|
|
int best, i, last, nxt;
|
|
|
|
|
|
|
|
pg = p->pgrp;
|
|
|
|
rlock(&pg->ns);
|
|
|
|
|
|
|
|
nxt = 0;
|
|
|
|
best = (int)(~0U>>1); /* largest 2's complement int */
|
|
|
|
|
|
|
|
last = 0;
|
|
|
|
if(mw->mh)
|
|
|
|
last = mw->cm->mountid;
|
|
|
|
|
|
|
|
for(i = 0; i < MNTHASH; i++) {
|
|
|
|
for(f = pg->mnthash[i]; f; f = f->hash) {
|
|
|
|
for(t = f->mount; t; t = t->next) {
|
|
|
|
if(mw->mh == 0 ||
|
|
|
|
(t->mountid > last && t->mountid < best)) {
|
|
|
|
mw->cm = t;
|
|
|
|
mw->mh = f;
|
|
|
|
best = mw->cm->mountid;
|
|
|
|
nxt = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(nxt == 0)
|
|
|
|
mw->mh = 0;
|
|
|
|
|
|
|
|
runlock(&pg->ns);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
procwrite(Chan *c, void *va, long n, int64_t off)
|
|
|
|
{
|
|
|
|
Proc *p, *t;
|
|
|
|
int i, id, l;
|
|
|
|
char **args, buf[ERRMAX];
|
|
|
|
uintptr_t offset;
|
|
|
|
|
|
|
|
if(c->qid.type & QTDIR)
|
|
|
|
error(Eisdir);
|
|
|
|
|
|
|
|
/* Use the remembered noteid in the channel rather
|
|
|
|
* than the process pgrpid
|
|
|
|
*/
|
|
|
|
if(QID(c->qid) == Qnotepg) {
|
|
|
|
pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((p = psincref(SLOT(c->qid))) == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
if(p->pid != PID(c->qid))
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
offset = off;
|
|
|
|
|
|
|
|
switch(QID(c->qid)){
|
|
|
|
case Qargs:
|
|
|
|
if(n == 0)
|
|
|
|
error(Eshort);
|
|
|
|
if(n >= ERRMAX)
|
|
|
|
error(Etoobig);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(buf, va, n);
|
|
|
|
args = jehanne_malloc(sizeof(char*)+n+1);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(args == nil)
|
|
|
|
error(Enomem);
|
|
|
|
args[0] = ((char*)args)+sizeof(char*);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(args[0], buf, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
l = n;
|
|
|
|
if(args[0][l-1] != 0)
|
|
|
|
args[0][l++] = 0;
|
|
|
|
if(p->setargs) /* setargs == 0 => args in stack from sysexec */
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(p->args);
|
2016-11-25 17:18:40 +01:00
|
|
|
p->nargs = l;
|
|
|
|
p->args = args;
|
|
|
|
p->setargs = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qmem:
|
|
|
|
if(p->state != Stopped)
|
|
|
|
error(Ebadctl);
|
|
|
|
|
|
|
|
n = procctlmemio(p, offset, n, va, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qregs:
|
|
|
|
if(offset >= sizeof(Ureg))
|
|
|
|
n = 0;
|
|
|
|
else if(offset+n > sizeof(Ureg))
|
|
|
|
n = sizeof(Ureg) - offset;
|
2017-08-11 01:47:15 +02:00
|
|
|
if(p->dbgreg == nil)
|
2016-11-25 17:18:40 +01:00
|
|
|
error(Enoreg);
|
|
|
|
setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qfpregs:
|
2017-08-11 01:47:15 +02:00
|
|
|
if(offset >= sizeof(FPsave))
|
|
|
|
n = 0;
|
|
|
|
else if(offset+n > sizeof(FPsave))
|
|
|
|
n = sizeof(FPsave) - offset;
|
|
|
|
memmove((uint8_t*)&p->fpsave+offset, va, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Qctl:
|
|
|
|
procctlreq(p, va, n);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Qnote:
|
|
|
|
if(p->kp)
|
|
|
|
error(Eperm);
|
|
|
|
if(n >= ERRMAX-1)
|
|
|
|
error(Etoobig);
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(buf, va, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
buf[n] = 0;
|
|
|
|
if(!postnote(p, 0, buf, NUser))
|
|
|
|
error("note not posted");
|
|
|
|
break;
|
|
|
|
case Qnoteid:
|
2017-04-19 23:33:14 +02:00
|
|
|
id = jehanne_atoi(va);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(id == p->pid) {
|
|
|
|
p->noteid = id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
for(i = 0; (t = psincref(i)) != nil; i++){
|
|
|
|
if(t->state == Dead || t->noteid != id){
|
|
|
|
psdecref(t);
|
|
|
|
continue;
|
|
|
|
}
|
2017-04-19 23:33:14 +02:00
|
|
|
if(jehanne_strcmp(p->user, t->user) != 0){
|
2016-11-25 17:18:40 +01:00
|
|
|
psdecref(t);
|
|
|
|
error(Eperm);
|
|
|
|
}
|
|
|
|
psdecref(t);
|
|
|
|
p->noteid = id;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(p->noteid != id)
|
|
|
|
error(Ebadarg);
|
|
|
|
break;
|
2016-12-15 22:42:01 +01:00
|
|
|
case Qwdir:
|
|
|
|
n = write_working_dir(p, va, n, off);
|
|
|
|
break;
|
2016-11-25 17:18:40 +01:00
|
|
|
default:
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
pprint("unknown qid %#llux in procwrite\n", c->qid.path);
|
|
|
|
error(Egreg);
|
|
|
|
}
|
|
|
|
poperror();
|
|
|
|
qunlock(&p->debug);
|
|
|
|
psdecref(p);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dev procdevtab = {
|
|
|
|
'p',
|
|
|
|
"proc",
|
|
|
|
|
|
|
|
devreset,
|
|
|
|
procinit,
|
|
|
|
devshutdown,
|
|
|
|
procattach,
|
|
|
|
procwalk,
|
|
|
|
procstat,
|
|
|
|
procopen,
|
|
|
|
devcreate,
|
|
|
|
procclose,
|
|
|
|
procread,
|
|
|
|
devbread,
|
|
|
|
procwrite,
|
|
|
|
devbwrite,
|
|
|
|
devremove,
|
|
|
|
procwstat,
|
|
|
|
};
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
proctext(Chan *c, Proc *p)
|
|
|
|
{
|
|
|
|
Chan *tc;
|
|
|
|
ProcSegment *s;
|
|
|
|
|
|
|
|
if(p->state==Dead)
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
rlock(&p->seglock);
|
|
|
|
s = p->seg[TSEG];
|
|
|
|
if(s == 0){
|
|
|
|
runlock(&p->seglock);
|
|
|
|
error(Enonexist);
|
|
|
|
}
|
|
|
|
|
|
|
|
tc = image_chan(s->image);
|
|
|
|
|
|
|
|
runlock(&p->seglock);
|
|
|
|
|
|
|
|
if(tc == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
if(p->pid != PID(c->qid))
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
return tc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
procstopwait(Proc *p, int ctl)
|
|
|
|
{
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
if(p->pdbg)
|
|
|
|
error(Einuse);
|
|
|
|
if(procstopped(p) || p->state == Broken)
|
|
|
|
return;
|
|
|
|
pid = p->pid;
|
|
|
|
if(pid == 0)
|
|
|
|
error(Eprocdied);
|
|
|
|
if(ctl != 0)
|
|
|
|
p->procctl = ctl;
|
2017-05-06 16:03:16 +02:00
|
|
|
if(p == up)
|
|
|
|
return;
|
2016-11-25 17:18:40 +01:00
|
|
|
p->pdbg = up;
|
|
|
|
qunlock(&p->debug);
|
|
|
|
up->psstate = "Stopwait";
|
|
|
|
if(waserror()) {
|
|
|
|
qlock(&p->debug);
|
|
|
|
p->pdbg = 0;
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
sleep(&up->sleep, procstopped, p);
|
|
|
|
poperror();
|
|
|
|
qlock(&p->debug);
|
|
|
|
if(p->pid != pid)
|
|
|
|
error(Eprocdied);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
procctlcloseone(Proc *p, Fgrp *f, int fd)
|
|
|
|
{
|
|
|
|
Chan *c;
|
|
|
|
|
|
|
|
c = f->fd[fd];
|
|
|
|
if(c == nil)
|
|
|
|
return;
|
|
|
|
f->fd[fd] = nil;
|
|
|
|
unlock(&f->l);
|
|
|
|
qunlock(&p->debug);
|
|
|
|
cclose(c);
|
|
|
|
qlock(&p->debug);
|
|
|
|
lock(&f->l);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
procctlclosefiles(Proc *p, int all, int fd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Fgrp *f;
|
|
|
|
|
|
|
|
f = p->fgrp;
|
|
|
|
if(f == nil)
|
|
|
|
error(Eprocdied);
|
|
|
|
|
|
|
|
lock(&f->l);
|
|
|
|
incref(&f->r);
|
|
|
|
if(all)
|
|
|
|
for(i = 0; i < f->maxfd; i++)
|
|
|
|
procctlcloseone(p, f, i);
|
|
|
|
else
|
|
|
|
procctlcloseone(p, f, fd);
|
|
|
|
unlock(&f->l);
|
|
|
|
closefgrp(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
procctlreq(Proc *p, char *va, int n)
|
|
|
|
{
|
|
|
|
int pri;
|
|
|
|
Cmdbuf *cb;
|
|
|
|
Cmdtab *ct;
|
|
|
|
|
|
|
|
if(p->kp) /* no ctl requests to kprocs */
|
|
|
|
error(Eperm);
|
|
|
|
|
|
|
|
cb = parsecmd(va, n);
|
|
|
|
if(waserror()){
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(cb);
|
2016-11-25 17:18:40 +01:00
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
|
|
|
|
ct = lookupcmd(cb, proccmd, nelem(proccmd));
|
|
|
|
|
|
|
|
switch(ct->index){
|
|
|
|
case CMclose:
|
2017-04-19 23:33:14 +02:00
|
|
|
procctlclosefiles(p, 0, jehanne_atoi(cb->f[1]));
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
case CMclosefiles:
|
|
|
|
procctlclosefiles(p, 1, 0);
|
|
|
|
break;
|
|
|
|
case CMhang:
|
|
|
|
p->hang = 1;
|
|
|
|
break;
|
|
|
|
case CMkill:
|
|
|
|
prockill(p, Proc_exitme, "sys: killed");
|
|
|
|
break;
|
|
|
|
case CMnohang:
|
|
|
|
p->hang = 0;
|
|
|
|
break;
|
|
|
|
case CMnoswap:
|
|
|
|
/* obsolete */
|
|
|
|
break;
|
|
|
|
case CMpri:
|
2017-04-19 23:33:14 +02:00
|
|
|
pri = jehanne_atoi(cb->f[1]);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(pri > PriNormal && !iseve())
|
|
|
|
error(Eperm);
|
|
|
|
procpriority(p, pri, 0);
|
|
|
|
break;
|
|
|
|
case CMfixedpri:
|
2017-04-19 23:33:14 +02:00
|
|
|
pri = jehanne_atoi(cb->f[1]);
|
2016-11-25 17:18:40 +01:00
|
|
|
if(pri > PriNormal && !iseve())
|
|
|
|
error(Eperm);
|
|
|
|
procpriority(p, pri, 1);
|
|
|
|
break;
|
|
|
|
case CMprivate:
|
|
|
|
p->privatemem = 1;
|
|
|
|
break;
|
|
|
|
case CMstart:
|
|
|
|
if(p->state != Stopped)
|
|
|
|
error(Ebadctl);
|
|
|
|
ready(p);
|
|
|
|
break;
|
|
|
|
case CMstartstop:
|
|
|
|
if(p->state != Stopped)
|
|
|
|
error(Ebadctl);
|
|
|
|
p->procctl = Proc_traceme;
|
|
|
|
ready(p);
|
|
|
|
procstopwait(p, Proc_traceme);
|
|
|
|
break;
|
|
|
|
case CMstartsyscall:
|
|
|
|
if(p->state != Stopped)
|
|
|
|
error(Ebadctl);
|
|
|
|
p->procctl = Proc_tracesyscall;
|
|
|
|
ready(p);
|
|
|
|
procstopwait(p, Proc_tracesyscall);
|
|
|
|
break;
|
|
|
|
case CMstop:
|
|
|
|
procstopwait(p, Proc_stopme);
|
|
|
|
break;
|
|
|
|
case CMwaitstop:
|
|
|
|
procstopwait(p, 0);
|
|
|
|
break;
|
|
|
|
case CMwired:
|
2017-04-19 23:33:14 +02:00
|
|
|
procwired(p, jehanne_atoi(cb->f[1]));
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
case CMtrace:
|
|
|
|
switch(cb->nf){
|
|
|
|
case 1:
|
|
|
|
p->trace ^= 1;
|
|
|
|
break;
|
|
|
|
case 2:
|
2017-04-19 23:33:14 +02:00
|
|
|
p->trace = (jehanne_atoi(cb->f[1]) != 0);
|
2016-11-25 17:18:40 +01:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error("args");
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
poperror();
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_free(cb);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procstopped(void *a)
|
|
|
|
{
|
|
|
|
Proc *p = a;
|
|
|
|
return p->state == Stopped;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
procctlmemio(Proc *p, uintptr_t offset, int n, void *va, int read)
|
|
|
|
{
|
|
|
|
char *k;
|
|
|
|
PagePointer page;
|
|
|
|
ProcSegment *s;
|
|
|
|
uint8_t *b;
|
|
|
|
uintptr_t l, mmuphys = 0;
|
|
|
|
|
|
|
|
s = proc_segment(p, offset);
|
|
|
|
if(s == nil)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
if(offset+n >= s->top)
|
|
|
|
n = s->top-offset;
|
|
|
|
|
|
|
|
if(!segment_fault(&mmuphys, &offset, s, read ? FaultRead : FaultWrite))
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
page = segment_page(s, (uintptr_t)offset);
|
|
|
|
if(page == 0)
|
|
|
|
error(Ebadarg);
|
|
|
|
|
|
|
|
k = page_kmap(page);
|
|
|
|
l = PGSZ - (offset&(PGSZ-1));
|
|
|
|
if(n > l)
|
|
|
|
n = l;
|
|
|
|
|
|
|
|
if(waserror()) {
|
|
|
|
page_kunmap(page, &k);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
b = (uint8_t*)k;
|
|
|
|
b += offset&(PGSZ-1);
|
|
|
|
if(read == 1){
|
|
|
|
/* caller is reading: the destination buffer is at va
|
|
|
|
* and it can fault if not yet loaded
|
|
|
|
*/
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(va, b, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
} else {
|
|
|
|
/* caller is writing: the source buffer is at va */
|
2017-04-19 23:33:14 +02:00
|
|
|
jehanne_memmove(b, va, n);
|
2016-11-25 17:18:40 +01:00
|
|
|
}
|
|
|
|
poperror();
|
|
|
|
page_kunmap(page, &k);
|
|
|
|
|
|
|
|
if(read == 0)
|
|
|
|
p->newtlb = 1;
|
|
|
|
|
|
|
|
return n;
|
|
|
|
}
|