skel(3) → skelfs(4)
The original intention was to put devskel in to the kernel to detach what it provides from devsrv. That is not a good reason, just move it to userspace. auth/box has been changed to exec skelfs instead of relying on '#z'.
This commit is contained in:
parent
c7c0ff5db6
commit
c12022fd8c
7 changed files with 351 additions and 283 deletions
|
@ -1,35 +0,0 @@
|
||||||
.TH SKEL 3
|
|
||||||
.SH NAME
|
|
||||||
skel \- skeleton builder
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B bind #z/\fIskel\fR
|
|
||||||
.I dir
|
|
||||||
.PP
|
|
||||||
.B bind #zd/\fIskel\fR
|
|
||||||
.I dir
|
|
||||||
.PP
|
|
||||||
.B bind #ze/
|
|
||||||
.I dir
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.PP
|
|
||||||
This device serves a single child directory with a single empty child
|
|
||||||
file. The name of these files is determined by the first walk away
|
|
||||||
from the root. After which, the hierarchy for that attached session
|
|
||||||
becomes stable. The
|
|
||||||
.B d
|
|
||||||
attach option causes the child file to be an empty directory. The
|
|
||||||
.B e
|
|
||||||
attach option presents a completly empty root directory.
|
|
||||||
.SH EXAMPLES
|
|
||||||
Skeleton files can be used for constructing arbitrary bind targets.
|
|
||||||
.EX
|
|
||||||
.IP
|
|
||||||
bind -b '#zd/newroot' /
|
|
||||||
bind '#zd/bin' /newroot
|
|
||||||
bind '#z/walk' /newroot/bin
|
|
||||||
bind /bin/walk /newroot/bin/walk
|
|
||||||
bind /newroot /
|
|
||||||
walk /
|
|
||||||
.EE
|
|
||||||
.SH SOURCE
|
|
||||||
.B /sys/src/9/port/devskel.c
|
|
65
sys/man/4/skelfs
Normal file
65
sys/man/4/skelfs
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
.TH SKELFS 4
|
||||||
|
.SH NAME
|
||||||
|
skelfs \- build directory skeletons
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B skelfs
|
||||||
|
[
|
||||||
|
.B -i
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.B -t
|
||||||
|
.I mode
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.B -s
|
||||||
|
.I service
|
||||||
|
]
|
||||||
|
[
|
||||||
|
.I mnt
|
||||||
|
]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.I Skelfs
|
||||||
|
generates directory skeletons
|
||||||
|
to assist in building namespaces.
|
||||||
|
Skeletons are generated on demand
|
||||||
|
by walking through the root directory.
|
||||||
|
A skeleon is a directory containing a single empty child.
|
||||||
|
The name of this child is defined by the first walk taken
|
||||||
|
away from the root. For example the hierarchy for a skeleton
|
||||||
|
named 'echo' would be:
|
||||||
|
.PP
|
||||||
|
.EX
|
||||||
|
/
|
||||||
|
/echo/
|
||||||
|
/echo/echo
|
||||||
|
.EE
|
||||||
|
.PP
|
||||||
|
The
|
||||||
|
.I mode
|
||||||
|
dictates what form the innermost child file takes. The
|
||||||
|
.B file
|
||||||
|
and
|
||||||
|
.B dir
|
||||||
|
modes cause the child to be an empty file or directory
|
||||||
|
respecively. The
|
||||||
|
.B empty
|
||||||
|
mode instead serves no skeletons, causing the root
|
||||||
|
directory to always be empty.
|
||||||
|
A client may override the mode by providing
|
||||||
|
its own selection as an attach option. If a
|
||||||
|
mode is not provided,
|
||||||
|
.B file
|
||||||
|
is assumed.
|
||||||
|
.PP
|
||||||
|
The skeletons generated by
|
||||||
|
.I skelfs
|
||||||
|
are anonmyous. Clients will never see the
|
||||||
|
skeletons of other clients, nor can a client revisit
|
||||||
|
a previous skeleton.
|
||||||
|
.PP
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
.B auth/box
|
||||||
|
in
|
||||||
|
.IR auth (8).
|
||||||
|
.SH SOURCE
|
||||||
|
.B /sys/src/cmd/skelfs.c
|
|
@ -18,7 +18,6 @@ dev
|
||||||
kprof
|
kprof
|
||||||
fs
|
fs
|
||||||
dtracy
|
dtracy
|
||||||
skel
|
|
||||||
|
|
||||||
ether netif
|
ether netif
|
||||||
bridge netif log
|
bridge netif log
|
||||||
|
|
|
@ -41,7 +41,6 @@ dev
|
||||||
segment
|
segment
|
||||||
vmx
|
vmx
|
||||||
dtracy
|
dtracy
|
||||||
skel
|
|
||||||
|
|
||||||
link
|
link
|
||||||
# devpccard pci
|
# devpccard pci
|
||||||
|
|
|
@ -1,239 +0,0 @@
|
||||||
#include "u.h"
|
|
||||||
#include "../port/lib.h"
|
|
||||||
#include "mem.h"
|
|
||||||
#include "dat.h"
|
|
||||||
#include "fns.h"
|
|
||||||
#include "../port/error.h"
|
|
||||||
|
|
||||||
#include "netif.h"
|
|
||||||
|
|
||||||
typedef struct Skel Skel;
|
|
||||||
struct Skel {
|
|
||||||
RWlock;
|
|
||||||
int ref;
|
|
||||||
char name[KNAMELEN];
|
|
||||||
char mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
QLock;
|
|
||||||
ulong path;
|
|
||||||
} skelalloc;
|
|
||||||
|
|
||||||
enum{
|
|
||||||
Qroot,
|
|
||||||
Qdir,
|
|
||||||
Qskel,
|
|
||||||
};
|
|
||||||
|
|
||||||
static Chan*
|
|
||||||
skelattach(char *spec)
|
|
||||||
{
|
|
||||||
Chan *c;
|
|
||||||
Skel *f;
|
|
||||||
uvlong path;
|
|
||||||
|
|
||||||
c = devattach('z', spec);
|
|
||||||
|
|
||||||
f = mallocz(sizeof *f, 1);
|
|
||||||
if(f == nil)
|
|
||||||
exhausted("memory");
|
|
||||||
if(waserror()){
|
|
||||||
free(f);
|
|
||||||
nexterror();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(spec == nil)
|
|
||||||
f->mode = 'f';
|
|
||||||
else
|
|
||||||
f->mode = spec[0];
|
|
||||||
|
|
||||||
eqlock(&skelalloc);
|
|
||||||
path = skelalloc.path++;
|
|
||||||
qunlock(&skelalloc);
|
|
||||||
|
|
||||||
poperror();
|
|
||||||
mkqid(&c->qid, NETQID(path, Qroot), path, QTDIR);
|
|
||||||
f->ref = 1;
|
|
||||||
c->aux = f;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
step(Chan *c, Dir *dp, int direction)
|
|
||||||
{
|
|
||||||
Skel *f;
|
|
||||||
Qid qid;
|
|
||||||
ulong perm;
|
|
||||||
int path;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
perm = 0555|DMDIR;
|
|
||||||
path = NETTYPE(c->qid.path);
|
|
||||||
f = c->aux;
|
|
||||||
rlock(f);
|
|
||||||
if(waserror()){
|
|
||||||
runlock(f);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
name = f->name;
|
|
||||||
|
|
||||||
path += direction;
|
|
||||||
if(!f->name[0] && path > Qroot)
|
|
||||||
error(Enonexist);
|
|
||||||
|
|
||||||
switch(path){
|
|
||||||
case Qroot-1:
|
|
||||||
case Qroot:
|
|
||||||
mkqid(&qid, Qroot, 0, QTDIR);
|
|
||||||
name = "#z";
|
|
||||||
break;
|
|
||||||
case Qdir:
|
|
||||||
mkqid(&qid, Qdir, 0, QTDIR);
|
|
||||||
break;
|
|
||||||
case Qskel:
|
|
||||||
switch(f->mode){
|
|
||||||
case 'd':
|
|
||||||
mkqid(&qid, Qskel, 0, QTDIR);
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
default:
|
|
||||||
mkqid(&qid, Qskel, 0, QTFILE);
|
|
||||||
perm = 0666;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error(Enonexist);
|
|
||||||
}
|
|
||||||
|
|
||||||
qid.vers = NETID(c->qid.path);
|
|
||||||
qid.path = NETQID(qid.vers, qid.path);
|
|
||||||
devdir(c, qid, name, 0, eve, perm, dp);
|
|
||||||
runlock(f);
|
|
||||||
poperror();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
skelgen(Chan *c, char *name, Dirtab*, int, int s, Dir *dp)
|
|
||||||
{
|
|
||||||
Skel *f;
|
|
||||||
|
|
||||||
switch(s){
|
|
||||||
case DEVDOTDOT:
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
s++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
f = c->aux;
|
|
||||||
if(name && NETTYPE(c->qid.path) == Qroot){
|
|
||||||
wlock(f);
|
|
||||||
if(!f->name[0] && f->mode != 'e')
|
|
||||||
utfecpy(f->name, &f->name[sizeof f->name-1], name);
|
|
||||||
wunlock(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return step(c, dp, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Walkqid*
|
|
||||||
skelwalk(Chan *c, Chan *nc, char **name, int nname)
|
|
||||||
{
|
|
||||||
Walkqid *wq;
|
|
||||||
Skel *f;
|
|
||||||
|
|
||||||
wq = devwalk(c, nc, name, nname, nil, 0, skelgen);
|
|
||||||
if(wq == nil || wq->clone == nil)
|
|
||||||
return wq;
|
|
||||||
|
|
||||||
f = c->aux;
|
|
||||||
wlock(f);
|
|
||||||
if(f->ref <= 0)
|
|
||||||
panic("devskel ref");
|
|
||||||
f->ref++;
|
|
||||||
wunlock(f);
|
|
||||||
return wq;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Chan*
|
|
||||||
skelopen(Chan *c, int omode)
|
|
||||||
{
|
|
||||||
if(!(c->qid.type & QTDIR))
|
|
||||||
error(Eperm);
|
|
||||||
if(omode != OREAD)
|
|
||||||
error(Ebadarg);
|
|
||||||
|
|
||||||
c->mode = omode;
|
|
||||||
c->flag |= COPEN;
|
|
||||||
c->offset = 0;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
skelclose(Chan *c)
|
|
||||||
{
|
|
||||||
Skel *f;
|
|
||||||
|
|
||||||
f = c->aux;
|
|
||||||
wlock(f);
|
|
||||||
f->ref--;
|
|
||||||
if(f->ref == 0){
|
|
||||||
wunlock(f);
|
|
||||||
free(f);
|
|
||||||
} else
|
|
||||||
wunlock(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
skelread(Chan *c, void *va, long n, vlong)
|
|
||||||
{
|
|
||||||
return devdirread(c, va, n, nil, 0, skelgen);
|
|
||||||
}
|
|
||||||
|
|
||||||
static long
|
|
||||||
skelwrite(Chan*, void*, long, vlong)
|
|
||||||
{
|
|
||||||
error(Ebadusefd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
skelstat(Chan *c, uchar *db, int n)
|
|
||||||
{
|
|
||||||
Dir dir;
|
|
||||||
|
|
||||||
if(step(c, &dir, 0) < 0)
|
|
||||||
error(Enonexist);
|
|
||||||
|
|
||||||
n = convD2M(&dir, db, n);
|
|
||||||
if(n < BIT16SZ)
|
|
||||||
error(Eshortstat);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dev skeldevtab = {
|
|
||||||
'z',
|
|
||||||
"skel",
|
|
||||||
|
|
||||||
devreset,
|
|
||||||
devinit,
|
|
||||||
devshutdown,
|
|
||||||
skelattach,
|
|
||||||
skelwalk,
|
|
||||||
skelstat,
|
|
||||||
skelopen,
|
|
||||||
devcreate,
|
|
||||||
skelclose,
|
|
||||||
skelread,
|
|
||||||
devbread,
|
|
||||||
skelwrite,
|
|
||||||
devbwrite,
|
|
||||||
devremove,
|
|
||||||
devwstat,
|
|
||||||
};
|
|
|
@ -29,7 +29,7 @@ binderr(char *new, char *old, int flag)
|
||||||
dash[1] = 'a';
|
dash[1] = 'a';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
print("bind %s %s %s\n", dash, new, old);
|
fprint(2, "bind %s %s %s\n", dash, new, old);
|
||||||
}
|
}
|
||||||
if(bind(new, old, flag) < 0)
|
if(bind(new, old, flag) < 0)
|
||||||
sysfatal("bind: %r");
|
sysfatal("bind: %r");
|
||||||
|
@ -72,10 +72,10 @@ sandbox(char **names, int *flags, int nname)
|
||||||
Dir *d;
|
Dir *d;
|
||||||
int i, j, n;
|
int i, j, n;
|
||||||
|
|
||||||
snprint(rootskel, sizeof rootskel, "#zd/newroot.%d", getpid());
|
snprint(rootskel, sizeof rootskel, "/mnt/d/newroot.%d", getpid());
|
||||||
binderr(rootskel, "/", MBEFORE);
|
binderr(rootskel, "/", MBEFORE);
|
||||||
|
|
||||||
newroot = rootskel + strlen("#zd");
|
newroot = rootskel + strlen("/mnt/d");
|
||||||
|
|
||||||
for(j = 0; j < nname; j++){
|
for(j = 0; j < nname; j++){
|
||||||
if(names[j] == nil)
|
if(names[j] == nil)
|
||||||
|
@ -97,9 +97,9 @@ sandbox(char **names, int *flags, int nname)
|
||||||
if(d == nil)
|
if(d == nil)
|
||||||
continue;
|
continue;
|
||||||
if(d->mode & DMDIR)
|
if(d->mode & DMDIR)
|
||||||
snprint(skel, sizeof skel, "#zd/%s", parts[i]);
|
snprint(skel, sizeof skel, "/mnt/d/%s", parts[i]);
|
||||||
else
|
else
|
||||||
snprint(skel, sizeof skel, "#zf/%s", parts[i]);
|
snprint(skel, sizeof skel, "/mnt/f/%s", parts[i]);
|
||||||
free(d);
|
free(d);
|
||||||
binderr(skel, dir, MBEFORE);
|
binderr(skel, dir, MBEFORE);
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,31 @@ sandbox(char **names, int *flags, int nname)
|
||||||
binderr(newroot, "/", MREPL);
|
binderr(newroot, "/", MREPL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
skelfs(void)
|
||||||
|
{
|
||||||
|
int p[2];
|
||||||
|
int dfd;
|
||||||
|
|
||||||
|
pipe(p);
|
||||||
|
switch(rfork(RFFDG|RFREND|RFPROC|RFNAMEG)){
|
||||||
|
case -1:
|
||||||
|
sysfatal("fork");
|
||||||
|
case 0:
|
||||||
|
close(p[1]);
|
||||||
|
dup(p[0], 0);
|
||||||
|
dup(p[0], 1);
|
||||||
|
execl("/bin/skelfs", "skelfs", debug > 1 ? "-Di" : "-i", nil);
|
||||||
|
sysfatal("exec /bin/skelfs: %r");
|
||||||
|
}
|
||||||
|
close(p[0]);
|
||||||
|
dfd = dup(p[1], -1);
|
||||||
|
if(mount(p[1], -1, "/mnt/f", MREPL, "file") < 0)
|
||||||
|
sysfatal("/mnt/f mount setup: %r");
|
||||||
|
if(mount(dfd, -1, "/mnt/d", MREPL, "dir") < 0)
|
||||||
|
sysfatal("/mnt/d mount setup: %r");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
usage(void)
|
usage(void)
|
||||||
{
|
{
|
||||||
|
@ -129,8 +154,10 @@ main(int argc, char **argv)
|
||||||
nparts = 0;
|
nparts = 0;
|
||||||
memset(devs, 0, sizeof devs);
|
memset(devs, 0, sizeof devs);
|
||||||
ARGBEGIN{
|
ARGBEGIN{
|
||||||
|
case 'D':
|
||||||
|
debug++;
|
||||||
case 'd':
|
case 'd':
|
||||||
debug = 1;
|
debug++;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
parts[nparts] = EARGF(usage());
|
parts[nparts] = EARGF(usage());
|
||||||
|
@ -164,6 +191,7 @@ main(int argc, char **argv)
|
||||||
argv[0] = b;
|
argv[0] = b;
|
||||||
|
|
||||||
rfork(RFNAMEG|RFFDG);
|
rfork(RFNAMEG|RFFDG);
|
||||||
|
skelfs();
|
||||||
dfd = open("/dev/drivers", OWRITE|OCEXEC);
|
dfd = open("/dev/drivers", OWRITE|OCEXEC);
|
||||||
if(dfd < 0)
|
if(dfd < 0)
|
||||||
sysfatal("could not /dev/drivers: %r");
|
sysfatal("could not /dev/drivers: %r");
|
||||||
|
@ -172,7 +200,7 @@ main(int argc, char **argv)
|
||||||
sandbox(parts, mflags, nparts);
|
sandbox(parts, mflags, nparts);
|
||||||
|
|
||||||
if(debug)
|
if(debug)
|
||||||
print("chdev %s\n", devs);
|
fprint(2, "chdev %s\n", devs);
|
||||||
|
|
||||||
if(devs[0] != '\0'){
|
if(devs[0] != '\0'){
|
||||||
if(fprint(dfd, "chdev & %s", devs) <= 0)
|
if(fprint(dfd, "chdev & %s", devs) <= 0)
|
||||||
|
|
251
sys/src/cmd/skelfs.c
Normal file
251
sys/src/cmd/skelfs.c
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <9p.h>
|
||||||
|
|
||||||
|
typedef struct Skel Skel;
|
||||||
|
struct Skel {
|
||||||
|
char name[64];
|
||||||
|
char mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
static uvlong sessions;
|
||||||
|
static char defmode;
|
||||||
|
|
||||||
|
enum{
|
||||||
|
Qroot,
|
||||||
|
Qdir,
|
||||||
|
Qskel,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define qtype(x) (((ulong)x)&0x1f)
|
||||||
|
#define qsess(x) ((((ulong)x))>>5)
|
||||||
|
#define mkqid(i,t) ((((ulong)i)<<5)|(t))
|
||||||
|
|
||||||
|
static int
|
||||||
|
step(Fid *f, int way, Qid *res, Dir *dp)
|
||||||
|
{
|
||||||
|
Skel *s;
|
||||||
|
int path;
|
||||||
|
char *name;
|
||||||
|
ulong perm;
|
||||||
|
|
||||||
|
s = f->aux;
|
||||||
|
name = s->name;
|
||||||
|
perm = 0550|DMDIR;
|
||||||
|
path = qtype(f->qid.path) + way;
|
||||||
|
if(!name[0] && way > 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(path < 0)
|
||||||
|
goto Root;
|
||||||
|
switch(path){
|
||||||
|
Root:
|
||||||
|
case Qroot:
|
||||||
|
name = "/";
|
||||||
|
/* fallthrough */
|
||||||
|
case Qdir:
|
||||||
|
res->type = QTDIR;
|
||||||
|
break;
|
||||||
|
case Qskel:
|
||||||
|
switch(s->mode){
|
||||||
|
case 'd':
|
||||||
|
res->type = QTDIR;
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
default:
|
||||||
|
res->type = QTFILE;
|
||||||
|
perm = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
res->vers = qsess(f->qid.path);
|
||||||
|
res->path = mkqid(res->vers, path);
|
||||||
|
if(dp){
|
||||||
|
dp->mode = perm;
|
||||||
|
dp->name = estrdup9p(name);
|
||||||
|
dp->uid = estrdup9p("sys");
|
||||||
|
dp->gid = estrdup9p("sys");
|
||||||
|
dp->qid = *res;
|
||||||
|
dp->length = 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dirgen(int i, Dir *d, void *a)
|
||||||
|
{
|
||||||
|
Fid *f;
|
||||||
|
Qid q;
|
||||||
|
|
||||||
|
if(i > 0)
|
||||||
|
return -1;
|
||||||
|
f = a;
|
||||||
|
return step(f, 1, &q, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fidclunk(Fid *fid)
|
||||||
|
{
|
||||||
|
free(fid->aux);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
fsclone(Fid *old, Fid *new, void*)
|
||||||
|
{
|
||||||
|
Skel *s, *s2;
|
||||||
|
|
||||||
|
s = old->aux;
|
||||||
|
s2 = emalloc9p(sizeof *s2);
|
||||||
|
if(s2 == nil)
|
||||||
|
return "out of memory";
|
||||||
|
memset(s2, 0, sizeof *s2);
|
||||||
|
|
||||||
|
s2->mode = s->mode;
|
||||||
|
utfecpy(s2->name, &s2->name[sizeof s2->name-1], s->name);
|
||||||
|
new->aux = s2;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
fswalk1(Fid *old, char *name, void*)
|
||||||
|
{
|
||||||
|
Skel *s;
|
||||||
|
|
||||||
|
if(strcmp("..", name) == 0){
|
||||||
|
step(old, -1, &old->qid, nil);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
s = old->aux;
|
||||||
|
if(!s->name[0] && qtype(old->qid.path) == Qroot && s->mode != 'e'){
|
||||||
|
utfecpy(s->name, &s->name[sizeof s->name-1], name);
|
||||||
|
old->qid.vers = sessions++;
|
||||||
|
old->qid.path = mkqid(old->qid.vers, qtype(old->qid.path));
|
||||||
|
} else if(strcmp(name, s->name) != 0)
|
||||||
|
return "does not exist";
|
||||||
|
|
||||||
|
if(step(old, 1, &old->qid, nil) < 0)
|
||||||
|
return "does not exist";
|
||||||
|
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fswalk(Req *r)
|
||||||
|
{
|
||||||
|
walkandclone(r, fswalk1, fsclone, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsattach(Req *r)
|
||||||
|
{
|
||||||
|
Skel s;
|
||||||
|
Fid root;
|
||||||
|
char *spec;
|
||||||
|
Qid *q;
|
||||||
|
|
||||||
|
spec = r->ifcall.aname;
|
||||||
|
if(spec && spec[0] != '\0')
|
||||||
|
s.mode = spec[0];
|
||||||
|
else
|
||||||
|
s.mode = defmode;
|
||||||
|
|
||||||
|
q = &r->fid->qid;
|
||||||
|
q->vers = sessions++;
|
||||||
|
q->path = mkqid(q->vers, Qroot);
|
||||||
|
q->type = QTDIR;
|
||||||
|
r->ofcall.qid = *q;
|
||||||
|
|
||||||
|
s.name[0] = '\0';
|
||||||
|
root.aux = &s;
|
||||||
|
respond(r, fsclone(&root, r->fid, nil));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsstat(Req *r)
|
||||||
|
{
|
||||||
|
Qid q;
|
||||||
|
|
||||||
|
if(step(r->fid, 0, &q, &r->d) < 0)
|
||||||
|
respond(r, "does not exist");
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsread(Req *r)
|
||||||
|
{
|
||||||
|
dirread9p(r, dirgen, r->fid);
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fsopen(Req *r)
|
||||||
|
{
|
||||||
|
r->ofcall.mode = r->ifcall.mode;
|
||||||
|
if(r->ifcall.mode != OREAD)
|
||||||
|
respond(r, "permission denied");
|
||||||
|
else
|
||||||
|
respond(r, nil);
|
||||||
|
}
|
||||||
|
|
||||||
|
Srv fs=
|
||||||
|
{
|
||||||
|
.attach= fsattach,
|
||||||
|
.open= fsopen,
|
||||||
|
.read= fsread,
|
||||||
|
.stat= fsstat,
|
||||||
|
.walk= fswalk,
|
||||||
|
.destroyfid= fidclunk
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: %s [ -Di ] [ -s service ] [ -t mode ] [ mntpt ]\n", argv0);
|
||||||
|
exits("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *s, *mode;
|
||||||
|
int stdio;
|
||||||
|
|
||||||
|
s = nil;
|
||||||
|
stdio = 0;
|
||||||
|
defmode = 'f';
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'D':
|
||||||
|
chatty9p++;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
s = EARGF(usage());
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
stdio = 1;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
mode = EARGF(usage());
|
||||||
|
defmode = mode[0];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if(stdio == 0){
|
||||||
|
postmountsrv(&fs, s, argc ? argv[0] : "/mnt/skel", MREPL);
|
||||||
|
exits(nil);
|
||||||
|
}
|
||||||
|
fs.infd = 0;
|
||||||
|
fs.outfd = 1;
|
||||||
|
srv(&fs);
|
||||||
|
exits(nil);
|
||||||
|
}
|
Loading…
Reference in a new issue