kernel: move chdir to libc using devself/devproc

Added wdir to devself and devproc:

- read '#0/wdir' to get the working directory of the calling process
  NOTE that a read(fd, nil, -1) will return the negated length
  of the working directory, just in case you want to
  allocate the memory required

- read '/proc/n/wdir' to know the working directory of process n
  (read(fd, nil, -1) still returns the negated length)

- write '#0/wdir' to change the working directory of the calling process
  NOTE: no offset is allowed and the provided string must
  be null terminated

- write '/proc/n/wdir' to change the working directory of process n
  NOTE: no offset is allowed and the provided string must
  be null terminated; moreover if another process change the working
  directory change during the write, the current process will
  receive an error.

In libc updated getwd() and chdir().
Also modified pwd to get advantage of the new file.

To test, run /arch/amd64/qa/kern/wdir.rc or simply try

	% pwd
	/usr/glenda
	% echo -n /tmp > /proc/$pid/wdir
        % pwd
        /tmp
        % cat '#0/wdir' && echo
        /tmp

The expected use cases for wdir in devproc are rio and acme.

Also, note that we could theoretically remove the cd builtin
from rc and simply implement it as a rc function.
We don't do that to preserve rc portability to other OS.
This commit is contained in:
Giacomo Tesio 2016-12-15 22:42:01 +01:00
parent c6de6b66e9
commit 99855d60d6
20 changed files with 357 additions and 308 deletions

33
qa/kern/wdir.rc Normal file
View File

@ -0,0 +1,33 @@
#!/cmd/rc
rm -fr /tmp/abcdefghijklmnopqrstuvwxyz/
dir=/tmp/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz/abcdefghijklmnopqrstuvwxyz
mkdir -p $dir
cd $dir
cwd=`{pwd}
if ( ! ~ $dir $cwd ) {
echo FAIL: '''pwd''' returned $cwd instead of '$dir'
exit FAIL
}
cwd=`{cat '#0/wdir'}
if ( ! ~ $dir $cwd ) {
echo FAIL: '''cat #0/wdir''' returned $cwd instead of '$dir'
exit FAIL
}
ppath=/proc/$pid/wdir
cwd=`{cat $ppath}
if ( ! ~ $dir $cwd ) {
echo FAIL: cat $ppath returned $cwd instead of '$dir'
exit FAIL
}
rm -fr /tmp/abcdefghijklmnopqrstuvwxyz/
echo PASS
exit PASS

View File

@ -20,41 +20,6 @@
int verbose = 1; int verbose = 1;
#define asm_nsec() ({ \
register long __ret asm ("rax"); \
__asm__ __volatile__ ( \
"syscall" \
: "=r" (__ret) \
: "0"(19) \
: "cc", "rcx", "r11", "memory" \
); \
__ret; })
#define asm_mount(/* int */ fd, /* int */ afd, /* char* */ old, /* int */ flag, /* char* */ aname, /* int */ mdev) ({ \
register long r10 asm("r10") = flag; \
register long r8 asm("r8") = (uintptr_t)aname; \
register long r9 asm("r9") = mdev; \
register int __ret asm ("eax"); \
__asm__ __volatile__ ( \
"syscall" \
: "=r" (__ret) \
: "0"(16), "D"(fd), "S"(afd), "d"(old), "r"(r10), "r"(r8), "r"(r9) \
: "cc", "rcx", "r11", "memory" \
); \
__ret; })
/*
long
asm_nsec(void)
{
register int *p1 asm ("r0");
register int *p2 asm ("r1");
register int *result asm ("r0");
asm ("sysint" : "=r" (result) : "0" (p1), "r" (p2));
return result ;
}
*/
void void
main(void) main(void)
{ {
@ -62,9 +27,9 @@ main(void)
uint64_t start, end; uint64_t start, end;
char *msg; char *msg;
start = asm_nsec(); start = sys_nsec();
sleep(1); sleep(1);
end = asm_nsec(); end = sys_nsec();
if (end <= start) if (end <= start)
ret = 1; ret = 1;
@ -80,7 +45,7 @@ main(void)
int fd; int fd;
fd = open("#|", ORDWR); fd = open("#|", ORDWR);
asm_mount(fd, -1, "/tmp", MREPL, "", 'M'); sys_mount(fd, -1, "/tmp", MREPL, "", 'M');
print("PASS\n"); print("PASS\n");
exits("PASS"); exits("PASS");

View File

@ -370,6 +370,7 @@ extern int atoi(const char*);
extern int32_t atol(const char*); extern int32_t atol(const char*);
extern int64_t atoll(const char*); extern int64_t atoll(const char*);
extern double charstod(int(*)(void*), void*); extern double charstod(int(*)(void*), void*);
extern int chdir(const char *dirname);
extern char* cleanname(char*); extern char* cleanname(char*);
extern int decrypt(void*, void*, int); extern int decrypt(void*, void*, int);
extern int encrypt(void*, void*, int); extern int encrypt(void*, void*, int);
@ -387,7 +388,7 @@ extern char* getenv(const char*);
extern int getfields(char*, char**, int, int, const char*); extern int getfields(char*, char**, int, int, const char*);
extern int gettokens(char *, char **, int, const char *); extern int gettokens(char *, char **, int, const char *);
extern char* getuser(void); extern char* getuser(void);
extern char* getwd(char*, int); extern long getwd(char*, int);
extern int iounit(int); extern int iounit(int);
extern int32_t labs(int32_t); extern int32_t labs(int32_t);
extern double ldexp(double, int); extern double ldexp(double, int);

View File

@ -71,7 +71,7 @@ threadmain(int argc, char *argv[])
name = av[0]; name = av[0];
} }
if(getwd(buf, sizeof buf) == 0) if(getwd(buf, sizeof buf) <= 0)
dir = "/"; dir = "/";
else else
dir = buf; dir = buf;
@ -301,7 +301,7 @@ fsloop(void* _)
break; break;
} }
} }
} }
void void
sendit(char *s) sendit(char *s)
@ -358,7 +358,7 @@ execevent(Window *w, Event *e, int (*command)(Window*, char*))
n = winread(w, e->q0, e->q1, s); n = winread(w, e->q0, e->q1, s);
s[n] = '\0'; s[n] = '\0';
needfree = 1; needfree = 1;
}else }else
if(na){ if(na){
t = emalloc(strlen(s)+1+na+2); t = emalloc(strlen(s)+1+na+2);
sprint(t, "%s %s", s, ea->b); sprint(t, "%s %s", s, ea->b);
@ -448,7 +448,7 @@ mainctl(void *v)
write(w->data, e->b, e->nb); write(w->data, e->b, e->nb);
pendingS += e->nr; pendingS += e->nr;
break; break;
case 'E': /* write to tag or body; body happens due to sendit */ case 'E': /* write to tag or body; body happens due to sendit */
delta = e->q1-e->q0; delta = e->q1-e->q0;
if(e->c2=='I'){ if(e->c2=='I'){
@ -463,7 +463,7 @@ mainctl(void *v)
fprint(2, "win msg: %C %C %d %d %d %d %q\n", fprint(2, "win msg: %C %C %d %d %d %d %q\n",
e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b); e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b);
break; break;
case 'F': /* generated by our actions (specifically case 'S' above) */ case 'F': /* generated by our actions (specifically case 'S' above) */
delta = e->q1-e->q0; delta = e->q1-e->q0;
if(e->c2=='D'){ if(e->c2=='D'){
@ -540,7 +540,7 @@ mainctl(void *v)
break; break;
} }
break; break;
case 'M': /* mouse */ case 'M': /* mouse */
delta = e->q1-e->q0; delta = e->q1-e->q0;
switch(e->c2){ switch(e->c2){
@ -548,14 +548,14 @@ mainctl(void *v)
case 'X': case 'X':
execevent(w, e, command); execevent(w, e, command);
break; break;
case 'l': /* reflect all searches back to acme */ case 'l': /* reflect all searches back to acme */
case 'L': case 'L':
if(e->flag & 2) if(e->flag & 2)
recvp(w->cevent); recvp(w->cevent);
winwriteevent(w, e); winwriteevent(w, e);
break; break;
case 'I': case 'I':
endpt += delta; endpt += delta;
if(e->q0 < hostpt) if(e->q0 < hostpt)
@ -574,7 +574,7 @@ mainctl(void *v)
case 'd': /* modify away; we don't care */ case 'd': /* modify away; we don't care */
case 'i': case 'i':
break; break;
default: default:
goto Unknown; goto Unknown;
} }

View File

@ -231,7 +231,7 @@ main(int argc, char **argv)
/* Tell the remote side the command to execute and where our working directory is */ /* Tell the remote side the command to execute and where our working directory is */
if(cflag) if(cflag)
writestr(data, cmd, "command", 0); writestr(data, cmd, "command", 0);
if(getwd(dat, sizeof(dat)) == 0) if(getwd(dat, sizeof(dat)) <= 0)
writestr(data, "NO", "dir", 0); writestr(data, "NO", "dir", 0);
else else
writestr(data, dat, "dir", 0); writestr(data, dat, "dir", 0);

View File

@ -1,10 +1,19 @@
/* /*
* This file is part of the UCB release of Plan 9. It is subject to the license * This file is part of Jehanne.
* terms in the LICENSE file found in the top-level directory of this *
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
* part of the UCB release of Plan 9, including this file, may be copied, *
* modified, propagated, or distributed except according to the terms contained * Jehanne is free software: you can redistribute it and/or modify
* in the LICENSE file. * 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/>.
*/ */
#include <u.h> #include <u.h>
@ -16,13 +25,23 @@
void void
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
char pathname[512]; long len;
char path[512];
char *ppath = path;
//USED(argc, argv); len = getwd(ppath, sizeof(path));
if(getwd(pathname, sizeof(pathname)) == 0) { if(len == 0)
fprint(2, "pwd: %r\n"); goto Error;
exits("getwd"); if(len < 0){
len = ~len;
ppath = malloc(len*sizeof(char));
if(getwd(ppath, len*sizeof(char)) <= 0)
goto Error;
} }
print("%s\n", pathname); print("%s\n", ppath);
exits(0); exits(0);
Error:
fprint(2, "pwd: %r\n");
exits("getwd");
} }

View File

@ -157,7 +157,7 @@ threadmain(int argc, char *argv[])
usage(); usage();
}ARGEND }ARGEND
if(getwd(buf, sizeof buf) == nil) if(getwd(buf, sizeof buf) <= 0)
startdir = estrdup("."); startdir = estrdup(".");
else else
startdir = estrdup(buf); startdir = estrdup(buf);
@ -324,7 +324,7 @@ shutdown(void * _, char *msg)
{ {
int i; int i;
static Lock shutdownlk; static Lock shutdownlk;
killprocs(); killprocs();
for(i=0; oknotes[i]; i++) for(i=0; oknotes[i]; i++)
if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0){ if(strncmp(oknotes[i], msg, strlen(oknotes[i])) == 0){
@ -344,7 +344,7 @@ killprocs(void)
for(i=0; i<nwindow; i++) for(i=0; i<nwindow; i++)
if(window[i]->notefd >= 0) if(window[i]->notefd >= 0)
write(window[i]->notefd, "hangup", 6); write(window[i]->notefd, "hangup", 6);
} }
void void
@ -418,7 +418,7 @@ int
whichcorner(Rectangle r, Point p) whichcorner(Rectangle r, Point p)
{ {
int i, j; int i, j;
i = portion(p.x, r.min.x, r.max.x); i = portion(p.x, r.min.x, r.max.x);
j = portion(p.y, r.min.y, r.max.y); j = portion(p.y, r.min.y, r.max.y);
return 3*j+i; return 3*j+i;
@ -995,7 +995,7 @@ bandsize(Window *w)
drawborder(r, 1); drawborder(r, 1);
or = r; or = r;
startp = p; startp = p;
while(mouse->buttons==but){ while(mouse->buttons==but){
p = onscreen(mouse->xy); p = onscreen(mouse->xy);
r = whichrect(w->screenr, p, which); r = whichrect(w->screenr, p, which);

View File

@ -1366,7 +1366,7 @@ main(int argc, char *argv[])
ret = extract(argv); ret = extract(argv);
break; break;
case Replace: case Replace:
if (getwd(origdir, sizeof origdir) == nil) if (getwd(origdir, sizeof origdir) <= 0)
strcpy(origdir, "/tmp"); strcpy(origdir, "/tmp");
ret = replace(argv); ret = replace(argv);
break; break;

View File

@ -64,9 +64,9 @@ dupopen(Chan *c, unsigned long omode)
int fd, twicefd; int fd, twicefd;
if(c->qid.type & QTDIR){ if(c->qid.type & QTDIR){
if(omode != 0) if(omode != OREAD)
error(Eisdir); error(Eisdir);
c->mode = 0; c->mode = OREAD;
c->flag |= COPEN; c->flag |= COPEN;
c->offset = 0; c->offset = 0;
return c; return c;

View File

@ -25,6 +25,12 @@
#include <trace.h> #include <trace.h>
#include "ureg.h" #include "ureg.h"
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)
*/
enum enum
{ {
Qdir, Qdir,
@ -47,6 +53,7 @@ enum
Qwait, Qwait,
Qprofile, Qprofile,
Qsyscall, Qsyscall,
Qwdir,
}; };
enum enum
@ -76,23 +83,25 @@ enum{
}; };
#define STATSIZE (2*KNAMELEN+NUMSIZE+9*NUMSIZE + 1) #define STATSIZE (2*KNAMELEN+NUMSIZE+9*NUMSIZE + 1)
/* /* In Plan 9 status, fd, and ns were left fully readable (0444)
* Status, fd, and ns are left fully readable (0444) because of their use in debugging, * because of their use in debugging, particularly on shared servers.
* particularly on shared servers. *
* Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000 * 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.
*/ */
Dirtab procdir[] = Dirtab procdir[] =
{ {
"args", {Qargs}, 0, 0660, "args", {Qargs}, 0, 0660,
"ctl", {Qctl}, 0, 0000, "ctl", {Qctl}, 0, 0000,
"fd", {Qfd}, 0, 0444, "fd", {Qfd}, 0, 0440,
"fpregs", {Qfpregs}, 0, 0000, "fpregs", {Qfpregs}, 0, 0000,
"kregs", {Qkregs}, sizeof(Ureg), 0400, "kregs", {Qkregs}, sizeof(Ureg), 0400,
"mem", {Qmem}, 0, 0000, "mem", {Qmem}, 0, 0000,
"note", {Qnote}, 0, 0000, "note", {Qnote}, 0, 0000,
"noteid", {Qnoteid}, 0, 0664, "noteid", {Qnoteid}, 0, 0664,
"notepg", {Qnotepg}, 0, 0000, "notepg", {Qnotepg}, 0, 0000,
"ns", {Qns}, 0, 0444, "ns", {Qns}, 0, 0440,
"proc", {Qproc}, 0, 0400, "proc", {Qproc}, 0, 0400,
"regs", {Qregs}, sizeof(Ureg), 0000, "regs", {Qregs}, sizeof(Ureg), 0000,
"segment", {Qsegment}, 0, 0444, "segment", {Qsegment}, 0, 0444,
@ -100,6 +109,7 @@ Dirtab procdir[] =
"text", {Qtext}, 0, 0000, "text", {Qtext}, 0, 0000,
"wait", {Qwait}, 0, 0400, "wait", {Qwait}, 0, 0400,
"syscall", {Qsyscall}, 0, 0400, "syscall", {Qsyscall}, 0, 0400,
"wdir", {Qwdir}, 0, 0640,
}; };
static static
@ -124,7 +134,7 @@ Cmdtab proccmd[] = {
/* /*
* Qids are, in path: * Qids are, in path:
* 4 bits of file type (qids above) * 5 bits of file type (qids above)
* 23 bits of process slot number + 1 * 23 bits of process slot number + 1
* in vers, * in vers,
* 32 bits of pid, for consistency checking * 32 bits of pid, for consistency checking
@ -232,6 +242,14 @@ procgen(Chan *c, char *name, Dirtab *tab, int _1, int s, Dir *dp)
len = p->nwait; /* incorrect size, but >0 means there's something to read */ len = p->nwait; /* incorrect size, but >0 means there's something to read */
break; break;
} }
switch(QID(tab->qid)){
case Qwdir:
/* file length might be relevant to the caller to
* malloc enough space in the buffer
*/
len = 1 + strlen(p->dot->path->s);
break;
}
mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
devdir(c, qid, tab->name, len, p->user, perm, dp); devdir(c, qid, tab->name, len, p->user, perm, dp);
@ -424,6 +442,17 @@ procopen(Chan *c, unsigned long omode)
c->pgrpid.vers = p->noteid; c->pgrpid.vers = p->noteid;
break; break;
case Qwdir:
if(p == up) /* self write is always allowed */
break;
if(omode > ORDWR)
error(Eperm);
if(strcmp(up->user, p->user) != 0 /* process owner can read/write */
|| !iseve() /* host owner can read */
|| (omode&OWRITE) != 0)
error(Eperm);
break;
default: default:
poperror(); poperror();
qunlock(&p->debug); qunlock(&p->debug);
@ -1058,6 +1087,10 @@ procread(Chan *c, void *va, long n, int64_t off)
r = procfds(p, va, n, offset); r = procfds(p, va, n, offset);
psdecref(p); psdecref(p);
return r; return r;
case Qwdir:
r = read_working_dir(p, va, n, off);
psdecref(p);
return r;
} }
error(Egreg); error(Egreg);
return 0; /* not reached */ return 0; /* not reached */
@ -1213,6 +1246,9 @@ procwrite(Chan *c, void *va, long n, int64_t off)
if(p->noteid != id) if(p->noteid != id)
error(Ebadarg); error(Ebadarg);
break; break;
case Qwdir:
n = write_working_dir(p, va, n, off);
break;
default: default:
poperror(); poperror();
qunlock(&p->debug); qunlock(&p->debug);

View File

@ -215,7 +215,7 @@ segmentopen(Chan *c, int omode)
switch(TYPE(c)){ switch(TYPE(c)){
case Qtopdir: case Qtopdir:
case Qsegdir: case Qsegdir:
if(omode != 0) if(omode != OREAD)
error(Eisdir); error(Eisdir);
break; break;
case Qctl: case Qctl:

View File

@ -37,6 +37,7 @@ typedef enum SelfNodes
Qppid, Qppid,
Qsegments, Qsegments,
Qpipes, Qpipes,
Qwdir,
} SelfNodes; } SelfNodes;
typedef enum SegmentsCmd typedef enum SegmentsCmd
@ -65,9 +66,49 @@ static Dirtab selfdir[]={
"ppid", {Qppid}, 0, 0, "ppid", {Qppid}, 0, 0,
"segments", {Qsegments}, 0, 0644, "segments", {Qsegments}, 0, 0644,
"pipes", {Qpipes}, 0, 0, "pipes", {Qpipes}, 0, 0,
"wdir", {Qwdir}, 0, 0644,
}; };
static int
selfgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
{
long length;
if(tab == 0)
return -1;
if(i == DEVDOTDOT){
if(QID(c->qid) != Qdir)
panic("selfwalk %llux", c->qid.path);
devdir(c, selfdir[0].qid, "#0", 0, up->user, selfdir[0].perm, dp);
return 1;
}
if(name){
for(i=1; i<ntab; i++)
if(strcmp(tab[i].name, name) == 0)
break;
if(i==ntab)
return -1;
tab += i;
}else{
/* skip over the first element, that for . itself */
i++;
if(i >= ntab)
return -1;
tab += i;
}
if(tab->qid.path == Qwdir) {
/* file length might be relevant to the caller to
* malloc enough space in the buffer
*/
length = 1 + strlen(up->dot->path->s);
} else {
length = tab->length;
}
devdir(c, tab->qid, tab->name, length, up->user, tab->perm, dp);
return 1;
}
static Chan* static Chan*
selfattach(Chan *c, Chan *ac, char *spec, int flags) selfattach(Chan *c, Chan *ac, char *spec, int flags)
{ {
@ -77,23 +118,80 @@ selfattach(Chan *c, Chan *ac, char *spec, int flags)
static Walkqid* static Walkqid*
selfwalk(Chan *c, Chan *nc, char **name, int nname) selfwalk(Chan *c, Chan *nc, char **name, int nname)
{ {
return devwalk(c, nc, name, nname, selfdir, nelem(selfdir), devgen); return devwalk(c, nc, name, nname, selfdir, nelem(selfdir), selfgen);
} }
static long static long
selfstat(Chan *c, uint8_t *dp, long n) selfstat(Chan *c, uint8_t *dp, long n)
{ {
return devstat(c, dp, n, selfdir, nelem(selfdir), devgen); return devstat(c, dp, n, selfdir, nelem(selfdir), selfgen);
} }
static Chan* static Chan*
selfopen(Chan *c, unsigned long omode) selfopen(Chan *c, unsigned long omode)
{ {
c->aux = nil; c->aux = nil;
c = devopen(c, omode, selfdir, nelem(selfdir), devgen); c = devopen(c, omode, selfdir, nelem(selfdir), selfgen);
return c; return c;
} }
long
read_working_dir(Proc* p, void *va, long n, int64_t off)
{
int i, j;
char *path;
Chan *dot;
dot = up->dot;
path = dot->path->s;
i = 1 + strlen(path);
if(va == nil){
/* the user is actually asking for the space */
if(off != 0 && off != ~0) {
/* #0/wdir does not allow offset in read */
error("offset reading wdir size");
}
errorl("not enough space in buffer", ~i);
}
if(off > i)
return 0;
j = i - off;
if(n < j)
j = n;
memmove(va, path, j);
return j;
}
long
write_working_dir(Proc* p, void *va, long n, int64_t off)
{
Chan *c, *dot;
char *path, *epath;
dot = p->dot;
path = va;
epath = vmemchr(path, 0, n);
if(n <= 0)
error(Ebadarg);
if(off != 0 && off != ~0)
error("offset writing wdir");
if(epath-path>=n)
error("no terminal zero writing wdir");
c = namec(path, Atodir, 0, 0);
if(CASV(&p->dot, dot, c)){
cclose(dot);
} else {
cclose(c);
error("race writing wdir");
}
return 0;
}
static long static long
selfread(Chan *c, void *va, long n, int64_t off) selfread(Chan *c, void *va, long n, int64_t off)
{ {
@ -104,6 +202,8 @@ selfread(Chan *c, void *va, long n, int64_t off)
offset = off; offset = off;
switch(QID(c->qid)){ switch(QID(c->qid)){
case Qdir:
return devdirread(c, va, n, selfdir, nelem(selfdir), selfgen);
case Qsegments: case Qsegments:
rlock(&up->seglock); rlock(&up->seglock);
j = 0; j = 0;
@ -127,6 +227,8 @@ selfread(Chan *c, void *va, long n, int64_t off)
exhausted("segments"); exhausted("segments");
memmove(va, &statbuf[offset], n); memmove(va, &statbuf[offset], n);
return n; return n;
case Qwdir:
return read_working_dir(up, va, n, off);
default: default:
error(Egreg); error(Egreg);
} }
@ -271,10 +373,10 @@ selfwrite(Chan *c, void *va, long n, int64_t off)
default: default:
error(Egreg); error(Egreg);
case Qsegments: case Qsegments:
n = procsegctl(up, va, n); return procsegctl(up, va, n);
break; case Qwdir:
return write_working_dir(up, va, n, off);
} }
return n;
} }
static int static int

View File

@ -1,21 +1,3 @@
/*
* 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/>.
*/
/* This device has been ported from 9front. /* This device has been ported from 9front.
*/ */
#include "u.h" #include "u.h"

View File

@ -6,13 +6,6 @@
#include "fns.h" #include "fns.h"
#include "../port/error.h" #include "../port/error.h"
//char *faulttypes[] = {
//[FT_WRITE] "write",
//[FT_READ] "read",
//[FT_EXEC] "exec"
//};
int int
fault(uintptr_t addr, uintptr_t pc, int ftype) fault(uintptr_t addr, uintptr_t pc, int ftype)
{ {
@ -70,132 +63,6 @@ fault(uintptr_t addr, uintptr_t pc, int ftype)
return -1; return -1;
} }
//int
//fixfault(Segment *s, uintptr_t addr, int ftype, int dommuput)
//{
//int type;
//Pte **p, *etp;
//uintptr_t soff;
//uintmem mmuphys;
//Page **pg, *old, *new;
//Page *(*fn)(Segment*, uintptr_t);
//uintptr_t pgsize;
//Pages *pages;
//pages = s->pages; /* TO DO: segwalk */
//pgsize = 1<<pages->lg2pgsize;
//addr &= ~(pgsize-1);
//soff = addr-s->pages->base;
//p = &pages->map[soff/pages->ptemapmem];
//if(*p == nil)
//*p = ptealloc();
//etp = *p;
//pg = &etp->pages[(soff&(pages->ptemapmem-1))>>pages->lg2pgsize];
//if(pg < etp->first)
//etp->first = pg;
//if(pg > etp->last)
//etp->last = pg;
//type = s->type&SG_TYPE;
//if(*pg == nil){
//switch(type){
//case SG_BSS: /* Zero fill on demand */
//case SG_SHARED:
//case SG_STACK:
//new = newpage(1, s->pages->lg2pgsize, &s->lk);
//if(new == nil)
//return -1;
//*pg = new;
//break;
//case SG_LOAD:
//case SG_TEXT: /* demand load */
//case SG_DATA:
//if(!loadimagepage(s->image, s, pg, addr))
//return -1;
//break;
//case SG_PHYSICAL:
//fn = s->pseg->pgalloc;
//if(fn != nil)
//*pg = (*fn)(s, addr);
//else {
//new = smalloc(sizeof(Page));
//new->pa = s->pseg->pa+(addr-s->pages->base);
//new->r.ref = 1;
//new->lg2size = s->pseg->lg2pgsize;
//if(new->lg2size == 0)
//new->lg2size = PGSHFT; /* TO DO */
//*pg = new;
//}
//break;
//default:
//panic("fault on demand");
//break;
//}
//}
//mmuphys = 0;
//switch(type) {
//default:
//panic("fault");
//break;
//case SG_TEXT:
//DBG("text pg %#p: %#p -> %#P %d\n", pg, addr, (*pg)->pa, (*pg)->r.ref);
//mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
//break;
//case SG_BSS:
//case SG_SHARED:
//case SG_STACK:
//case SG_DATA: /* copy on write */
//DBG("data pg %#p: %#p -> %#P %d\n", pg, addr, (*pg)->pa, (*pg)->r.ref);
///*
//* It's only possible to copy on write if
//* we're the only user of the segment.
//*/
//if(ftype != FT_WRITE && sys->copymode == 0 && s->r.ref == 1) {
//mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
//break;
//}
//old = *pg;
//if(old->r.ref > 1){
///* shared (including image pages): make private writable copy */
//new = newpage(0, s->pages->lg2pgsize, &s->lk);
//if(new != nil)
//copypage(old, new);
//*pg = new;
//putpage(old);
//if(new == nil)
//return -1;
//DBG("data' pg %#p: %#p -> %#P %d\n", *pg, addr, old->pa, old->r.ref);
//}else if(old->r.ref <= 0)
//panic("fault: page %#p %#P ref %d <= 0", old, old->pa, old->r.ref);
//mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
//break;
//case SG_PHYSICAL:
//mmuphys = PPN((*pg)->pa) | PTEVALID;
//if((s->pseg->attr & SG_WRITE))
//mmuphys |= PTEWRITE;
//if((s->pseg->attr & SG_CACHED) == 0)
//mmuphys |= PTEUNCACHED;
//break;
//}
//runlock(&s->lk);
//if(dommuput)
//mmuput(addr, mmuphys, *pg);
//if(ftype == FT_EXEC)
//peekAtExecFaults(addr);
//return 0;
//}
/* /*
* Called only in a system call * Called only in a system call
*/ */
@ -225,7 +92,7 @@ void*
validaddr(void* addr, long len, int write) validaddr(void* addr, long len, int write)
{ {
if(!okaddr(PTR2UINT(addr), len, write)){ if(!okaddr(PTR2UINT(addr), len, write)){
pprint("trap: invalid address %#p/%lud in sys call pc=%#P\n", addr, len, userpc(nil)); pprint("trap: invalid address %#p/%ld in sys call pc=%#P\n", addr, len, userpc(nil));
postnote(up, 1, "sys: bad address in syscall", NDebug); postnote(up, 1, "sys: bad address in syscall", NDebug);
error(Ebadarg); error(Ebadarg);
} }

View File

@ -597,14 +597,24 @@ mountfix(Chan *c, uint8_t *op, int32_t n, int32_t maxn)
} }
long long
syspread(int fd, void *p, int32_t n, int64_t off) syspread(int fd, void *p, long n, int64_t off)
{ {
int32_t nn; int32_t nn;
long nnn; long nnn;
int sequential; int sequential;
Chan *c; Chan *c;
p = validaddr(p, n, 1); if(n >= 0)
p = validaddr(p, n, 1);
else if(p != nil) {
/* in Jehanne, a negative length can be meaningful to
* the target device/server, but with a negative length
* to read the buffer must be nil
*/
pprint("trap: invalid address %#p/%ld in sys call pc=%#P\n", p, n, userpc(nil));
postnote(up, 1, "sys: bad address in syscall", NDebug);
error(Ebadarg);
}
c = fdtochan(fd, OREAD, 1, 1); c = fdtochan(fd, OREAD, 1, 1);
@ -679,7 +689,7 @@ syspread(int fd, void *p, int32_t n, int64_t off)
} }
long long
syspwrite(int fd, void *p, int32_t n, int64_t off) syspwrite(int fd, void *p, long n, int64_t off)
{ {
long r; long r;
int sequential; int sequential;
@ -858,20 +868,6 @@ sysfstat(int fd, uint8_t* p, int n)
return r; return r;
} }
int
syschdir(char *aname)
{
Chan *c;
aname = validaddr(aname, 1, 0);
c = namec(aname, Atodir, 0, 0);
cclose(up->dot);
up->dot = c;
return 0;
}
/* white list of devices we allow mounting on. /* white list of devices we allow mounting on.
* At some point we can have build generate this if we ever * At some point we can have build generate this if we ever
* really start using it. * really start using it.

View File

@ -77,7 +77,7 @@ buildns(int newns, char *user, char *file)
/* make sure we managed to cd into the new name space */ /* make sure we managed to cd into the new name space */
if(newns && !cdroot){ if(newns && !cdroot){
path = malloc(1024); path = malloc(1024);
if(path == nil || getwd(path, 1024) == 0 || chdir(path) < 0) if(path == nil || getwd(path, 1024) <= 0 || chdir(path) < 0)
chdir("/"); chdir("/");
if(path != nil) if(path != nil)
free(path); free(path);
@ -222,7 +222,7 @@ unquote(char *s)
{ {
char *r, *w; char *r, *w;
int inquote; int inquote;
inquote = 0; inquote = 0;
for(r=w=s; *r; r++){ for(r=w=s; *r; r++){
if(*r != '\''){ if(*r != '\''){
@ -267,7 +267,7 @@ nextdollar(char *arg)
{ {
char *p; char *p;
int inquote; int inquote;
inquote = 0; inquote = 0;
for(p=arg; *p; p++){ for(p=arg; *p; p++){
if(*p == '\'') if(*p == '\'')

View File

@ -0,0 +1,38 @@
/*
* This file is part of Jehanne.
*
* Copyright (C) 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/>.
*/
#include <u.h>
#include <libc.h>
int
chdir(const char *dirname)
{
char buf[32];
int tmp, fd;
tmp = getpid();
snprint(buf, sizeof(buf), "/proc/%d/wdir", tmp);
fd = open(buf, OWRITE);
if(fd < 0)
fd = open("#0/wdir", OWRITE);
if(fd < 0)
return fd;
tmp = write(fd, dirname, 1+strlen(dirname));
close(fd);
return tmp;
}

View File

@ -1,26 +1,45 @@
/* /*
* This file is part of the UCB release of Plan 9. It is subject to the license * This file is part of Jehanne.
* terms in the LICENSE file found in the top-level directory of this *
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * Copyright (C) 2016 Giacomo Tesio <giacomo@tesio.it>
* part of the UCB release of Plan 9, including this file, may be copied, *
* modified, propagated, or distributed except according to the terms contained * Jehanne is free software: you can redistribute it and/or modify
* in the LICENSE file. * 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/>.
*/ */
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
char* /* Fills buf with the current workking directory.
*
* Returns
* - 0 on error
* - the negated length of the working directory path if nbuf is too small
* - the (positive) length of the working directory on success
*/
long
getwd(char *buf, int nbuf) getwd(char *buf, int nbuf)
{ {
int n, fd; long n;
int fd;
fd = open(".", OREAD); fd = open("#0/wdir", OREAD);
if(fd < 0) if(fd < 0)
return nil; return 0;
n = fd2path(fd, buf, nbuf); n = read(fd, nil, -1);
if(n == ~0) /* an error occurred */
return 0;
if(nbuf >= ~n)
n = read(fd, buf, nbuf);
close(fd); close(fd);
if(n < 0) return n;
return nil;
return buf;
} }

View File

@ -38,6 +38,7 @@
"9sys/access.c", "9sys/access.c",
"9sys/announce.c", "9sys/announce.c",
"9sys/awakened.c", "9sys/awakened.c",
"9sys/chdir.c",
"9sys/convD2M.c", "9sys/convD2M.c",
"9sys/convM2D.c", "9sys/convM2D.c",
"9sys/cputime.c", "9sys/cputime.c",

View File

@ -65,19 +65,9 @@
}, },
{ {
"Args": [ "Args": [
"const char*" "int"
], ],
"Id": 4, "Id": 4,
"Name": "chdir",
"Ret": [
"int"
]
},
{
"Args": [
"int"
],
"Id": 5,
"Name": "close", "Name": "close",
"Ret": [ "Ret": [
"long" "long"
@ -89,7 +79,7 @@
"uint32_t", "uint32_t",
"uint32_t" "uint32_t"
], ],
"Id": 6, "Id": 5,
"Name": "create", "Name": "create",
"Ret": [ "Ret": [
"long" "long"
@ -100,7 +90,7 @@
"int32_t", "int32_t",
"int32_t" "int32_t"
], ],
"Id": 7, "Id": 6,
"Name": "dup", "Name": "dup",
"Ret": [ "Ret": [
"int32_t" "int32_t"
@ -111,7 +101,7 @@
"char*", "char*",
"int" "int"
], ],
"Id": 8, "Id": 7,
"Name": "errstr", "Name": "errstr",
"Ret": [ "Ret": [
"int" "int"
@ -122,7 +112,7 @@
"const char*", "const char*",
"const char**" "const char**"
], ],
"Id": 9, "Id": 8,
"Name": "exec", "Name": "exec",
"Ret": [ "Ret": [
"uintptr_t" "uintptr_t"
@ -132,7 +122,7 @@
"Args": [ "Args": [
"const char*" "const char*"
], ],
"Id": 10, "Id": 9,
"Name": "_exits", "Name": "_exits",
"Ret": [ "Ret": [
"int" "int"
@ -143,7 +133,7 @@
"int", "int",
"const char*" "const char*"
], ],
"Id": 11, "Id": 10,
"Name": "fauth", "Name": "fauth",
"Ret": [ "Ret": [
"int" "int"
@ -155,7 +145,7 @@
"const char*", "const char*",
"uint32_t" "uint32_t"
], ],
"Id": 12, "Id": 11,
"Name": "fd2path", "Name": "fd2path",
"Ret": [ "Ret": [
"int32_t" "int32_t"
@ -167,7 +157,7 @@
"uint8_t*", "uint8_t*",
"int" "int"
], ],
"Id": 13, "Id": 12,
"Name": "fstat", "Name": "fstat",
"Ret": [ "Ret": [
"long" "long"
@ -180,7 +170,7 @@
"const char*", "const char*",
"int" "int"
], ],
"Id": 14, "Id": 13,
"Name": "fversion", "Name": "fversion",
"Ret": [ "Ret": [
"int" "int"
@ -192,7 +182,7 @@
"const uint8_t*", "const uint8_t*",
"uint32_t" "uint32_t"
], ],
"Id": 15, "Id": 14,
"Name": "fwstat", "Name": "fwstat",
"Ret": [ "Ret": [
"long" "long"
@ -207,7 +197,7 @@
"const char*", "const char*",
"int" "int"
], ],
"Id": 16, "Id": 15,
"Name": "mount", "Name": "mount",
"Ret": [ "Ret": [
"int" "int"
@ -217,7 +207,7 @@
"Args": [ "Args": [
"int" "int"
], ],
"Id": 17, "Id": 16,
"Name": "noted", "Name": "noted",
"Ret": [ "Ret": [
"int" "int"
@ -227,14 +217,14 @@
"Args": [ "Args": [
"const void*" "const void*"
], ],
"Id": 18, "Id": 17,
"Name": "notify", "Name": "notify",
"Ret": [ "Ret": [
"int" "int"
] ]
}, },
{ {
"Id": 19, "Id": 18,
"Name": "nsec", "Name": "nsec",
"Ret": [ "Ret": [
"long" "long"
@ -245,7 +235,7 @@
"const char*", "const char*",
"uint32_t" "uint32_t"
], ],
"Id": 20, "Id": 19,
"Name": "open", "Name": "open",
"Ret": [ "Ret": [
"long" "long"
@ -255,10 +245,10 @@
"Args": [ "Args": [
"int", "int",
"void*", "void*",
"int", "long",
"long" "long"
], ],
"Id": 21, "Id": 20,
"Name": "pread", "Name": "pread",
"Ret": [ "Ret": [
"long" "long"
@ -268,10 +258,10 @@
"Args": [ "Args": [
"int", "int",
"const void*", "const void*",
"int", "long",
"long" "long"
], ],
"Id": 22, "Id": 21,
"Name": "pwrite", "Name": "pwrite",
"Ret": [ "Ret": [
"long" "long"
@ -281,7 +271,7 @@
"Args": [ "Args": [
"const char*" "const char*"
], ],
"Id": 23, "Id": 22,
"Name": "remove", "Name": "remove",
"Ret": [ "Ret": [
"long" "long"
@ -292,7 +282,7 @@
"const void*", "const void*",
"void*" "void*"
], ],
"Id": 24, "Id": 23,
"Name": "rendezvous", "Name": "rendezvous",
"Ret": [ "Ret": [
"void*" "void*"
@ -302,7 +292,7 @@
"Args": [ "Args": [
"uint32_t" "uint32_t"
], ],
"Id": 25, "Id": 24,
"Name": "rfork", "Name": "rfork",
"Ret": [ "Ret": [
"int" "int"
@ -314,7 +304,7 @@
"long", "long",
"int" "int"
], ],
"Id": 26, "Id": 25,
"Name": "seek", "Name": "seek",
"Ret": [ "Ret": [
"long" "long"
@ -325,7 +315,7 @@
"int*", "int*",
"int" "int"
], ],
"Id": 27, "Id": 26,
"Name": "semacquire", "Name": "semacquire",
"Ret": [ "Ret": [
"int" "int"
@ -336,7 +326,7 @@
"int*", "int*",
"int" "int"
], ],
"Id": 28, "Id": 27,
"Name": "semrelease", "Name": "semrelease",
"Ret": [ "Ret": [
"int" "int"
@ -347,7 +337,7 @@
"int*", "int*",
"uint64_t" "uint64_t"
], ],
"Id": 29, "Id": 28,
"Name": "tsemacquire", "Name": "tsemacquire",
"Ret": [ "Ret": [
"int" "int"
@ -358,7 +348,7 @@
"const char*", "const char*",
"const char*" "const char*"
], ],
"Id": 30, "Id": 29,
"Name": "unmount", "Name": "unmount",
"Ret": [ "Ret": [
"int" "int"
@ -368,7 +358,7 @@
"Args": [ "Args": [
"unsigned long" "unsigned long"
], ],
"Id": 31, "Id": 30,
"Name": "alarm", "Name": "alarm",
"Ret": [ "Ret": [
"long" "long"