--- /sys/src/9/port/devproc.c Fri Dec 7 22:53:55 2018+++ ../frontmods/port/devproc.c Fri Dec 7 23:24:24 2018@@ -91,7 +91,7 @@ "note", {Qnote}, 0, 0000, "noteid", {Qnoteid}, 0, 0664, "notepg", {Qnotepg}, 0, 0000,- "ns", {Qns}, 0, 0444,+ "ns", {Qns}, 0, 0644, "ppid", {Qppid}, 0, 0444, "proc", {Qproc}, 0, 0400, "regs", {Qregs}, sizeof(Ureg), 0000,@@ -155,10 +155,12 @@ #define NOTEID(q) ((q).vers) void procctlreq(Proc*, char*, int);+void procnsreq(Proc*, char*, int); long procctlmemio(Chan*, Proc*, uintptr, void*, long, int); Chan* proctext(Chan*, Proc*); int procstopped(void*); ulong procpagecount(Proc *);+long procbindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec, Proc* targp); static Traceevent *tevents; static Lock tlock;@@ -168,6 +170,177 @@ static int lenwatchpt(Proc *); +/* begin sysfile.c borrowed functions */+static void+punlockfgrp(Fgrp *f)+{+ int ex;++ ex = f->exceed;+ f->exceed = 0;+ unlock(f);+ if(ex)+ pprint("warning: process exceeds %d file descriptors\n", ex);+}++int+pgrowfd(Fgrp *f, int fd) /* fd is always >= 0 */+{+ Chan **newfd, **oldfd;++ if(fd < f->nfd)+ return 0;+ if(fd >= f->nfd+DELTAFD)+ return -1; /* out of range */+ /*+ * Unbounded allocation is unwise; besides, there are only 16 bits+ * of fid in 9P+ */+ if(f->nfd >= 5000){+ Exhausted:+ print("no free file descriptors\n");+ return -1;+ }+ newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));+ if(newfd == nil)+ goto Exhausted;+ oldfd = f->fd;+ memmove(newfd, oldfd, f->nfd*sizeof(Chan*));+ f->fd = newfd;+ free(oldfd);+ f->nfd += DELTAFD;+ if(fd > f->maxfd){+ if(fd/100 > f->maxfd/100)+ f->exceed = (fd/100)*100;+ f->maxfd = fd;+ }+ return 1;+}++/*+ * this assumes that the fgrp is locked+ */+int+pfindfreefd(Fgrp *f, int start)+{+ int fd;++ for(fd=start; fd<f->nfd; fd++)+ if(f->fd[fd] == 0)+ break;+ if(fd >= f->nfd && pgrowfd(f, fd) < 0)+ return -1;+ return fd;+}++Chan*+pfdtochan(int fd, int mode, int chkmnt, int iref, Proc *targp)+{+ Chan *c;+ Fgrp *f;++ c = 0;+ f = targp->fgrp;++ lock(f);+ if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {+ unlock(f);+ error(Ebadfd);+ }+ if(iref)+ incref(c);+ unlock(f);++ if(chkmnt && (c->flag&CMSG)) {+ if(iref)+ cclose(c);+ error(Ebadusefd);+ }++ if(mode<0 || c->mode==ORDWR)+ return c;++ if((mode&OTRUNC) && c->mode==OREAD) {+ if(iref)+ cclose(c);+ error(Ebadusefd);+ }++ if((mode&~OTRUNC) != c->mode) {+ if(iref)+ cclose(c);+ error(Ebadusefd);+ }++ return c;+}++int+pnewfd(Chan *c, Proc *targp)+{+ int fd;+ Fgrp *f;++ f = targp->fgrp;+ lock(f);+ fd = pfindfreefd(f, 0);+ if(fd < 0){+ punlockfgrp(f);+ return -1;+ }+ if(fd > f->maxfd)+ f->maxfd = fd;+ f->fd[fd] = c;+ punlockfgrp(f);+ return fd;+}++uintptr+psysopen(Proc *targp, va_list list)+{+ int fd;+ Chan *c;+ char *name;+ ulong mode;++ name = va_arg(list, char*);+ mode = va_arg(list, ulong);+ openmode(mode); /* error check only */+// validaddr(arg[0], 1, 0);+ c = pnamec(name, Aopen, mode, 0, targp);+ if(waserror()){+ cclose(c);+ nexterror();+ }+ fd = pnewfd(c, targp);+ if(fd < 0)+ error(Enofd);+ poperror();+ return (uintptr)fd;+}++void+pfdclose(int fd, int flag, Proc *targp)+{+ Chan *c;+ Fgrp *f = targp->fgrp;++ lock(f);+ c = fd <= f->maxfd ? f->fd[fd] : nil;+ if(c == nil || (flag != 0 && (c->flag&flag) == 0)){+ unlock(f);+ return;+ }+ f->fd[fd] = nil;+ if(fd == f->maxfd){+ while(fd > 0 && f->fd[fd] == nil)+ f->maxfd = --fd;+ }+ unlock(f);+ cclose(c);+}+/* End borrowed functions from sysfile.c */+ static int procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) {@@ -394,6 +567,10 @@ case Qsegment: case Qprofile: case Qns:+ if((omode != OREAD) && (p->privatemem))+ error(Eperm);+ break;+ case Qfd: if(omode != OREAD) error(Eperm);@@ -650,6 +827,8 @@ int2flag(cm->mflag, flag); if(strcmp(cm->to->path->s, "#M") == 0){ srv = srvname(cm->to->mchan);+ if(srv == nil)+ srv = zrvname(cm->to->mchan); i = snprint(buf, nbuf, (cm->spec && *cm->spec)? "mount %s %q %q %q\n": "mount %s %q %q\n", flag, srv? srv: cm->to->mchan->path->s, mh->from->path->s, cm->spec);@@ -1170,7 +1349,8 @@ eqlock(&p->debug); if(waserror()){- qunlock(&p->debug);+ if(p->debug.locked == 1)+ qunlock(&p->debug); nexterror(); } if(p->pid != PID(c->qid))@@ -1263,12 +1443,21 @@ case Qwatchpt: writewatchpt(p, va, n, off); break;+ case Qns:+// print("procnsreq on p, %s, %ld\n", a, n);+ if(p->debug.locked == 1)+ qunlock(&p->debug);+ nonone(p);+ procnsreq(p, va, n);+ break;+ default: print("unknown qid in procwrite\n"); error(Egreg); } poperror();- qunlock(&p->debug);+ if(p->debug.locked == 1)+ qunlock(&p->debug); return n; } @@ -1688,4 +1877,238 @@ p->newtlb = 1; return n;+}+/* modified version of bindmount from sysfile.c. This operates on a target process */++long+procbindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec, Proc* targp)+{+ int ret;+ Chan *c0, *c1, *ac, *bc;++ if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))+ error(Ebadarg);++ if(ismount){+ if(waserror()) {+ print("nsmod /proc mounts locked on process %uld\n", targp->pid);+ nexterror();+ }+ if(canqlock(&targp->procmount) == 0){+ error("mounts on this process via /proc locked by previous error");+ poperror();+ return -1;+ }+ poperror();++// validaddr((ulong)spec, 1, 0);+ spec = validnamedup(spec, 1);+ if(waserror()){+ free(spec);+ nexterror();+ }++ if(targp->pgrp->noattach)+ error(Enoattach);++ ac = nil;+ bc = pfdtochan(fd, ORDWR, 0, 1, targp);+ if(waserror()) {+ if(ac != nil)+ cclose(ac);+ cclose(bc);+ nexterror();+ }++ if(afd >= 0)+ ac = pfdtochan(afd, ORDWR, 0, 1, targp);++ c0 = mntattach(bc, ac, spec, flag&MCACHE);+ qunlock(&targp->procmount);+// print("c0 mntattach(bc, ac, spec, flag&MCACHE)\n");+ poperror(); /* ac bc */+ if(ac != nil)+ cclose(ac);+ cclose(bc);+ }else{+ spec = nil;+// validaddr((ulong)arg0, 1, 0);+// print("c0 = pnamec(%s, Abind, 0, 0, targp)\n", arg0);+ c0 = pnamec(arg0, Abind, 0, 0, targp);+ }++ if(waserror()){+ cclose(c0);+ nexterror();+ }+// validaddr((ulong)arg1, 1, 0);+// print("c1 = pnamec(%s, Abind, 0, 0, targp)\n", arg1);+ c1 = pnamec(arg1, Amount, 0, 0, targp);+ if(waserror()){+ cclose(c1);+ nexterror();+ }+// print("ret = pcmount(&c0, c1, flag, bogus.spec, targp)\n");+ ret = pcmount(&c0, c1, flag, spec, targp);++ poperror();+ cclose(c1);+ poperror();+ cclose(c0);+ if(ismount){+ pfdclose(fd, 0, targp);+ poperror();+ free(spec); + }+ return ret;+}++long+procunmount(char *name, char *old, Proc *targp)+{+ Chan *cmount, *cmounted;++ cmounted = nil;+// validaddr(arg[1], 1, 0);+ cmount = pnamec(old, Amount, 0, 0, targp);+ if(waserror()) {+ cclose(cmount);+ if(cmounted != nil)+ cclose(cmounted);+ nexterror();+ }+ if(name != nil) {+ /*+ * This has to be namec(..., Aopen, ...) because+ * if arg[0] is something like /srv/cs or /fd/0,+ * opening it is the only way to get at the real+ * Chan underneath.+ */+// validaddr(arg[0], 1, 0);+ cmounted = pnamec(name, Aopen, OREAD, 0, targp);+ }+ pcunmount(cmount, cmounted, targp);+ poperror();+ cclose(cmount);+ if(cmounted != nil)+ cclose(cmounted);+ return 0;+}++int+psysopenwrap(Proc *p, int nargs, ...)+{+ int fd;+ va_list args;+ va_start(args,nargs);+ fd=psysopen(p, args);+ va_end(args);+ return fd;+}++/* parses writes on the ns file converts to namespace operations */+/* the completed command is sent to procbindmount or procunmount */++void+procnsreq(Proc *p, char *va, int n)+{+ Cmdbuf *cbf;+ char *new, *old, *charflags, *spec;+ ulong flags;+ int fd;+ int countnf;++ flags=MREPL;+ countnf=1;+ spec = "";++ cbf = parsecmd(va, n);+ if(waserror()){+ free(cbf);+ nexterror();+ }++// print("cbf->nf=%d\n", cbf->nf);+ if((cbf->nf < 2) || (cbf->nf > 5)){+ error(Ebadarg);+ poperror();+ return;+ } else if(cbf->nf == 2){+ if(strcmp(cbf->f[0], "unmount") != 0){+ error(Ebadarg);+ poperror();+ return; + }+ new = nil;+ old = cbf->f[1];+ if(strncmp(old, "#|", 2)==0){+ error(Ebadsharp);+ poperror();+ return;+ }+// print("procunmount(everything from %s on %uld)\n", old, p->pid);+ procunmount(new, old, p);+ poperror();+ return; + } else if(cbf->nf == 3){+ new = cbf->f[1];+ old = cbf->f[2];+ } else {+ if(*(cbf->f[1]) == '-'){+ charflags = cbf->f[1];+ for(int i = 1; *(charflags+i) != '\0'; i++){+ if(*(charflags+i) == 'a')+ flags |= MAFTER;+ if(*(charflags+i) == 'b')+ flags |= MBEFORE;+ if(*(charflags+i) == 'c')+ flags |= MCREATE;+ if(*(charflags+i) == 'C')+ flags |= MCACHE;+ }+ countnf++;+ }+ new = cbf->f[countnf++];+ old = cbf->f[countnf++];+ if(countnf < cbf->nf){+ spec=cbf->f[countnf];+ }+ }+ if(strcmp(cbf->f[0], "bind")==0){+// print("procbindmount(0, -1, -1, %s, %s, %uld, nil, %uld)\n", new, old, flags, p->pid);+ procbindmount(0, -1, -1, new, old, flags, nil, p);+ } else if (strcmp(cbf->f[0], "mount")==0){+ if((strncmp(new, "#|", 2)==0) || (strncmp(old, "#|", 2)==0)){+ error(Ebadsharp);+ poperror();+ return;+ }+// print("psysopenwrap(targp, 2, %s, ORDWR)\n", new);+ fd=psysopenwrap(p, 2, new, ORDWR);+ if(fd < 0){+ error(Ebadfd);+ poperror();+ return;+ }+// print("procbindmount(1, %d, -1, nil, %s, %uld, spec %s, %uld)\n", fd, old, flags, spec, p->pid);+ procbindmount(1, fd, -1, nil, old, flags, spec, p);+ } else if (strcmp(cbf->f[0], "unmount")==0){+ /* forbid access to pipe devices */+ if((strncmp(new, "#|/", 3)==0) || (strncmp(old, "#|", 2)==0)){+ error(Ebadsharp);+ poperror();+ return;+ }+ /* forbid access to tls device */+ if((strncmp(new, "#a/", 3)==0) || (strncmp(old, "#a", 2)==0)){+ error(Ebadsharp);+ poperror();+ return;+ }+// print("procunmount(%s from %s on %uld)\n", new, old, p->pid);+ procunmount(new, old, p);+ }++ poperror();+ free(cbf); }
--- /sys/src/9/port/devproc.c Fri Dec 7 22:53:55 2018
+++ ../frontmods/port/devproc.c Fri Dec 7 23:24:24 2018
@@ -91,7 +91,7 @@
"note", {Qnote}, 0, 0000,
"noteid", {Qnoteid}, 0, 0664,
"notepg", {Qnotepg}, 0, 0000,
- "ns", {Qns}, 0, 0444,
+ "ns", {Qns}, 0, 0644,
"ppid", {Qppid}, 0, 0444,
"proc", {Qproc}, 0, 0400,
"regs", {Qregs}, sizeof(Ureg), 0000,
@@ -155,10 +155,12 @@
#define NOTEID(q) ((q).vers)
void procctlreq(Proc*, char*, int);
+void procnsreq(Proc*, char*, int);
long procctlmemio(Chan*, Proc*, uintptr, void*, long, int);
Chan* proctext(Chan*, Proc*);
int procstopped(void*);
ulong procpagecount(Proc *);
+long procbindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec, Proc* targp);
static Traceevent *tevents;
static Lock tlock;
@@ -168,6 +170,177 @@
static int lenwatchpt(Proc *);
+/* begin sysfile.c borrowed functions */
+static void
+punlockfgrp(Fgrp *f)
+{
+ int ex;
+
+ ex = f->exceed;
+ f->exceed = 0;
+ unlock(f);
+ if(ex)
+ pprint("warning: process exceeds %d file descriptors\n", ex);
+}
+
+int
+pgrowfd(Fgrp *f, int fd) /* fd is always >= 0 */
+{
+ Chan **newfd, **oldfd;
+
+ if(fd < f->nfd)
+ return 0;
+ if(fd >= f->nfd+DELTAFD)
+ return -1; /* out of range */
+ /*
+ * Unbounded allocation is unwise; besides, there are only 16 bits
+ * of fid in 9P
+ */
+ if(f->nfd >= 5000){
+ Exhausted:
+ print("no free file descriptors\n");
+ return -1;
+ }
+ newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
+ if(newfd == nil)
+ goto Exhausted;
+ oldfd = f->fd;
+ memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
+ f->fd = newfd;
+ free(oldfd);
+ f->nfd += DELTAFD;
+ if(fd > f->maxfd){
+ if(fd/100 > f->maxfd/100)
+ f->exceed = (fd/100)*100;
+ f->maxfd = fd;
+ }
+ return 1;
+}
+
+/*
+ * this assumes that the fgrp is locked
+ */
+int
+pfindfreefd(Fgrp *f, int start)
+{
+ int fd;
+
+ for(fd=start; fd<f->nfd; fd++)
+ if(f->fd[fd] == 0)
+ break;
+ if(fd >= f->nfd && pgrowfd(f, fd) < 0)
+ return -1;
+ return fd;
+}
+
+Chan*
+pfdtochan(int fd, int mode, int chkmnt, int iref, Proc *targp)
+{
+ Chan *c;
+ Fgrp *f;
+
+ c = 0;
+ f = targp->fgrp;
+
+ lock(f);
+ if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
+ unlock(f);
+ error(Ebadfd);
+ }
+ if(iref)
+ incref(c);
+ unlock(f);
+
+ if(chkmnt && (c->flag&CMSG)) {
+ if(iref)
+ cclose(c);
+ error(Ebadusefd);
+ }
+
+ if(mode<0 || c->mode==ORDWR)
+ return c;
+
+ if((mode&OTRUNC) && c->mode==OREAD) {
+ if(iref)
+ cclose(c);
+ error(Ebadusefd);
+ }
+
+ if((mode&~OTRUNC) != c->mode) {
+ if(iref)
+ cclose(c);
+ error(Ebadusefd);
+ }
+
+ return c;
+}
+
+int
+pnewfd(Chan *c, Proc *targp)
+{
+ int fd;
+ Fgrp *f;
+
+ f = targp->fgrp;
+ lock(f);
+ fd = pfindfreefd(f, 0);
+ if(fd < 0){
+ punlockfgrp(f);
+ return -1;
+ }
+ if(fd > f->maxfd)
+ f->maxfd = fd;
+ f->fd[fd] = c;
+ punlockfgrp(f);
+ return fd;
+}
+
+uintptr
+psysopen(Proc *targp, va_list list)
+{
+ int fd;
+ Chan *c;
+ char *name;
+ ulong mode;
+
+ name = va_arg(list, char*);
+ mode = va_arg(list, ulong);
+ openmode(mode); /* error check only */
+// validaddr(arg[0], 1, 0);
+ c = pnamec(name, Aopen, mode, 0, targp);
+ if(waserror()){
+ cclose(c);
+ nexterror();
+ }
+ fd = pnewfd(c, targp);
+ if(fd < 0)
+ error(Enofd);
+ poperror();
+ return (uintptr)fd;
+}
+
+void
+pfdclose(int fd, int flag, Proc *targp)
+{
+ Chan *c;
+ Fgrp *f = targp->fgrp;
+
+ lock(f);
+ c = fd <= f->maxfd ? f->fd[fd] : nil;
+ if(c == nil || (flag != 0 && (c->flag&flag) == 0)){
+ unlock(f);
+ return;
+ }
+ f->fd[fd] = nil;
+ if(fd == f->maxfd){
+ while(fd > 0 && f->fd[fd] == nil)
+ f->maxfd = --fd;
+ }
+ unlock(f);
+ cclose(c);
+}
+/* End borrowed functions from sysfile.c */
+
static int
procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
{
@@ -394,6 +567,10 @@
case Qsegment:
case Qprofile:
case Qns:
+ if((omode != OREAD) && (p->privatemem))
+ error(Eperm);
+ break;
+
case Qfd:
if(omode != OREAD)
error(Eperm);
@@ -650,6 +827,8 @@
int2flag(cm->mflag, flag);
if(strcmp(cm->to->path->s, "#M") == 0){
srv = srvname(cm->to->mchan);
+ if(srv == nil)
+ srv = zrvname(cm->to->mchan);
i = snprint(buf, nbuf, (cm->spec && *cm->spec)?
"mount %s %q %q %q\n": "mount %s %q %q\n", flag,
srv? srv: cm->to->mchan->path->s, mh->from->path->s, cm->spec);
@@ -1170,7 +1349,8 @@
eqlock(&p->debug);
if(waserror()){
- qunlock(&p->debug);
+ if(p->debug.locked == 1)
+ qunlock(&p->debug);
nexterror();
}
if(p->pid != PID(c->qid))
@@ -1263,12 +1443,21 @@
case Qwatchpt:
writewatchpt(p, va, n, off);
break;
+ case Qns:
+// print("procnsreq on p, %s, %ld\n", a, n);
+ if(p->debug.locked == 1)
+ qunlock(&p->debug);
+ nonone(p);
+ procnsreq(p, va, n);
+ break;
+
default:
print("unknown qid in procwrite\n");
error(Egreg);
}
poperror();
- qunlock(&p->debug);
+ if(p->debug.locked == 1)
+ qunlock(&p->debug);
return n;
}
@@ -1688,4 +1877,238 @@
p->newtlb = 1;
return n;
+}
+/* modified version of bindmount from sysfile.c. This operates on a target process */
+
+long
+procbindmount(int ismount, int fd, int afd, char* arg0, char* arg1, ulong flag, char* spec, Proc* targp)
+{
+ int ret;
+ Chan *c0, *c1, *ac, *bc;
+
+ if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
+ error(Ebadarg);
+
+ if(ismount){
+ if(waserror()) {
+ print("nsmod /proc mounts locked on process %uld\n", targp->pid);
+ nexterror();
+ }
+ if(canqlock(&targp->procmount) == 0){
+ error("mounts on this process via /proc locked by previous error");
+ poperror();
+ return -1;
+ }
+ poperror();
+
+// validaddr((ulong)spec, 1, 0);
+ spec = validnamedup(spec, 1);
+ if(waserror()){
+ free(spec);
+ nexterror();
+ }
+
+ if(targp->pgrp->noattach)
+ error(Enoattach);
+
+ ac = nil;
+ bc = pfdtochan(fd, ORDWR, 0, 1, targp);
+ if(waserror()) {
+ if(ac != nil)
+ cclose(ac);
+ cclose(bc);
+ nexterror();
+ }
+
+ if(afd >= 0)
+ ac = pfdtochan(afd, ORDWR, 0, 1, targp);
+
+ c0 = mntattach(bc, ac, spec, flag&MCACHE);
+ qunlock(&targp->procmount);
+// print("c0 mntattach(bc, ac, spec, flag&MCACHE)\n");
+ poperror(); /* ac bc */
+ if(ac != nil)
+ cclose(ac);
+ cclose(bc);
+ }else{
+ spec = nil;
+// validaddr((ulong)arg0, 1, 0);
+// print("c0 = pnamec(%s, Abind, 0, 0, targp)\n", arg0);
+ c0 = pnamec(arg0, Abind, 0, 0, targp);
+ }
+
+ if(waserror()){
+ cclose(c0);
+ nexterror();
+ }
+// validaddr((ulong)arg1, 1, 0);
+// print("c1 = pnamec(%s, Abind, 0, 0, targp)\n", arg1);
+ c1 = pnamec(arg1, Amount, 0, 0, targp);
+ if(waserror()){
+ cclose(c1);
+ nexterror();
+ }
+// print("ret = pcmount(&c0, c1, flag, bogus.spec, targp)\n");
+ ret = pcmount(&c0, c1, flag, spec, targp);
+
+ poperror();
+ cclose(c1);
+ poperror();
+ cclose(c0);
+ if(ismount){
+ pfdclose(fd, 0, targp);
+ poperror();
+ free(spec);
+ }
+ return ret;
+}
+
+long
+procunmount(char *name, char *old, Proc *targp)
+{
+ Chan *cmount, *cmounted;
+
+ cmounted = nil;
+// validaddr(arg[1], 1, 0);
+ cmount = pnamec(old, Amount, 0, 0, targp);
+ if(waserror()) {
+ cclose(cmount);
+ if(cmounted != nil)
+ cclose(cmounted);
+ nexterror();
+ }
+ if(name != nil) {
+ /*
+ * This has to be namec(..., Aopen, ...) because
+ * if arg[0] is something like /srv/cs or /fd/0,
+ * opening it is the only way to get at the real
+ * Chan underneath.
+ */
+// validaddr(arg[0], 1, 0);
+ cmounted = pnamec(name, Aopen, OREAD, 0, targp);
+ }
+ pcunmount(cmount, cmounted, targp);
+ poperror();
+ cclose(cmount);
+ if(cmounted != nil)
+ cclose(cmounted);
+ return 0;
+}
+
+int
+psysopenwrap(Proc *p, int nargs, ...)
+{
+ int fd;
+ va_list args;
+ va_start(args,nargs);
+ fd=psysopen(p, args);
+ va_end(args);
+ return fd;
+}
+
+/* parses writes on the ns file converts to namespace operations */
+/* the completed command is sent to procbindmount or procunmount */
+
+void
+procnsreq(Proc *p, char *va, int n)
+{
+ Cmdbuf *cbf;
+ char *new, *old, *charflags, *spec;
+ ulong flags;
+ int fd;
+ int countnf;
+
+ flags=MREPL;
+ countnf=1;
+ spec = "";
+
+ cbf = parsecmd(va, n);
+ if(waserror()){
+ free(cbf);
+ nexterror();
+ }
+
+// print("cbf->nf=%d\n", cbf->nf);
+ if((cbf->nf < 2) || (cbf->nf > 5)){
+ error(Ebadarg);
+ poperror();
+ return;
+ } else if(cbf->nf == 2){
+ if(strcmp(cbf->f[0], "unmount") != 0){
+ error(Ebadarg);
+ poperror();
+ return;
+ }
+ new = nil;
+ old = cbf->f[1];
+ if(strncmp(old, "#|", 2)==0){
+ error(Ebadsharp);
+ poperror();
+ return;
+ }
+// print("procunmount(everything from %s on %uld)\n", old, p->pid);
+ procunmount(new, old, p);
+ poperror();
+ return;
+ } else if(cbf->nf == 3){
+ new = cbf->f[1];
+ old = cbf->f[2];
+ } else {
+ if(*(cbf->f[1]) == '-'){
+ charflags = cbf->f[1];
+ for(int i = 1; *(charflags+i) != '\0'; i++){
+ if(*(charflags+i) == 'a')
+ flags |= MAFTER;
+ if(*(charflags+i) == 'b')
+ flags |= MBEFORE;
+ if(*(charflags+i) == 'c')
+ flags |= MCREATE;
+ if(*(charflags+i) == 'C')
+ flags |= MCACHE;
+ }
+ countnf++;
+ }
+ new = cbf->f[countnf++];
+ old = cbf->f[countnf++];
+ if(countnf < cbf->nf){
+ spec=cbf->f[countnf];
+ }
+ }
+ if(strcmp(cbf->f[0], "bind")==0){
+// print("procbindmount(0, -1, -1, %s, %s, %uld, nil, %uld)\n", new, old, flags, p->pid);
+ procbindmount(0, -1, -1, new, old, flags, nil, p);
+ } else if (strcmp(cbf->f[0], "mount")==0){
+ if((strncmp(new, "#|", 2)==0) || (strncmp(old, "#|", 2)==0)){
+ error(Ebadsharp);
+ poperror();
+ return;
+ }
+// print("psysopenwrap(targp, 2, %s, ORDWR)\n", new);
+ fd=psysopenwrap(p, 2, new, ORDWR);
+ if(fd < 0){
+ error(Ebadfd);
+ poperror();
+ return;
+ }
+// print("procbindmount(1, %d, -1, nil, %s, %uld, spec %s, %uld)\n", fd, old, flags, spec, p->pid);
+ procbindmount(1, fd, -1, nil, old, flags, spec, p);
+ } else if (strcmp(cbf->f[0], "unmount")==0){
+ /* forbid access to pipe devices */
+ if((strncmp(new, "#|/", 3)==0) || (strncmp(old, "#|", 2)==0)){
+ error(Ebadsharp);
+ poperror();
+ return;
+ }
+ /* forbid access to tls device */
+ if((strncmp(new, "#a/", 3)==0) || (strncmp(old, "#a", 2)==0)){
+ error(Ebadsharp);
+ poperror();
+ return;
+ }
+// print("procunmount(%s from %s on %uld)\n", new, old, p->pid);
+ procunmount(new, old, p);
+ }
+
+ poperror();
+ free(cbf);
}