/* * Clumsy hack to be able to create mountable files in /srv that * correspond to certain directories, kind of like an in-kernel exportfs: * * fd = open("#~/mntloop", ORDWR); * fprint(fd, "/mnt/foo"); * sfd = create("/srv/foo", ORDWR, 0666); * fprint(sfd, "%d", fd); * close(sfd); * close(fd); * * is almost equivalent to * * srvfs /mnt/foo foo * * but avoids the translation to 9P and back when you later * mount /srv/foo. There are a few inaccuracies compared * to what srvfs does: * * binds and mounts inside the tree rooted at /mnt/foo * in the original name space are not present when a * different name space mounts /srv/foo. * * if the exported tree is a kernel device, then the kernel * device will use the name of the user who mounted /srv/foo * (not the name of the user who exported it) for permissions checks. * * This is all so that we can provide a /srv/boot file even if the * root is from a kernel device. It's not intended for general use. */ #include "u.h"#include "lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h" enum { Qdir = 0, Qmntloop = 1}; static Chan*mntloopattach(char *spec){ Chan *c; c = devattach('~', spec); mkqid(&c->qid, Qdir, 0, QTDIR); return c;} static Dirtab dir[] = { "#~", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "mntloop", {Qmntloop, 0, 0}, 0, 0666,}; static intmntloopgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp){ if(s == DEVDOTDOT){ devdir(c, c->qid, "#~", 0, eve, DMDIR|0555, dp); return 1; } return devgen(c, name, dir, nelem(dir), s, dp);} static Walkqid*mntloopwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, nil, 0, mntloopgen);} static intmntloopstat(Chan *c, uchar *dp, int n){ return devstat(c, dp, n, nil, 0, mntloopgen);} static Chan*mntloopopen(Chan *c, int omode){ return devopen(c, omode, nil, 0, mntloopgen);} static voidmntloopclose(Chan *c){ if(c->aux) cclose(c->aux);} static longmntloopread(Chan *c, void *va, long n, vlong off){ error(Egreg); return -1;} static longmntloopwrite(Chan *c, void *va, long n, vlong off){ char *p; Chan *nc; if(c->aux || off != 0 || n >= BY2PG) error(Ebadarg); p = smalloc(n+1); memmove(p, va, n); p[n] = 0; if(waserror()){ free(p); nexterror(); } nc = namec(p, Atodir, 0, 0); free(p); poperror(); lock(&c->ref.lk); if(c->aux){ unlock(&c->ref.lk); cclose(nc); error(Ebadarg); } c->aux = nc; unlock(&c->ref.lk); return n;} Dev mntloopdevtab = { /* known to mntattach */ '~', "mntloop", devreset, devinit, devshutdown, mntloopattach, mntloopwalk, mntloopstat, mntloopopen, devcreate, mntloopclose, mntloopread, devbread, mntloopwrite, devbwrite, devremove, devwstat,};
/*
* Clumsy hack to be able to create mountable files in /srv that
* correspond to certain directories, kind of like an in-kernel exportfs:
*
* fd = open("#~/mntloop", ORDWR);
* fprint(fd, "/mnt/foo");
* sfd = create("/srv/foo", ORDWR, 0666);
* fprint(sfd, "%d", fd);
* close(sfd);
* close(fd);
*
* is almost equivalent to
*
* srvfs /mnt/foo foo
*
* but avoids the translation to 9P and back when you later
* mount /srv/foo. There are a few inaccuracies compared
* to what srvfs does:
*
* binds and mounts inside the tree rooted at /mnt/foo
* in the original name space are not present when a
* different name space mounts /srv/foo.
*
* if the exported tree is a kernel device, then the kernel
* device will use the name of the user who mounted /srv/foo
* (not the name of the user who exported it) for permissions checks.
*
* This is all so that we can provide a /srv/boot file even if the
* root is from a kernel device. It's not intended for general use.
*/
#include "u.h"
#include "lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "error.h"
enum {
Qdir = 0,
Qmntloop = 1
};
static Chan*
mntloopattach(char *spec)
{
Chan *c;
c = devattach('~', spec);
mkqid(&c->qid, Qdir, 0, QTDIR);
return c;
}
static Dirtab dir[] = {
"#~", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"mntloop", {Qmntloop, 0, 0}, 0, 0666,
};
static int
mntloopgen(Chan *c, char *name, Dirtab *tab, int ntab, int s, Dir *dp)
{
if(s == DEVDOTDOT){
devdir(c, c->qid, "#~", 0, eve, DMDIR|0555, dp);
return 1;
}
return devgen(c, name, dir, nelem(dir), s, dp);
}
static Walkqid*
mntloopwalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, nil, 0, mntloopgen);
}
static int
mntloopstat(Chan *c, uchar *dp, int n)
{
return devstat(c, dp, n, nil, 0, mntloopgen);
}
static Chan*
mntloopopen(Chan *c, int omode)
{
return devopen(c, omode, nil, 0, mntloopgen);
}
static void
mntloopclose(Chan *c)
{
if(c->aux)
cclose(c->aux);
}
static long
mntloopread(Chan *c, void *va, long n, vlong off)
{
error(Egreg);
return -1;
}
static long
mntloopwrite(Chan *c, void *va, long n, vlong off)
{
char *p;
Chan *nc;
if(c->aux || off != 0 || n >= BY2PG)
error(Ebadarg);
p = smalloc(n+1);
memmove(p, va, n);
p[n] = 0;
if(waserror()){
free(p);
nexterror();
}
nc = namec(p, Atodir, 0, 0);
free(p);
poperror();
lock(&c->ref.lk);
if(c->aux){
unlock(&c->ref.lk);
cclose(nc);
error(Ebadarg);
}
c->aux = nc;
unlock(&c->ref.lk);
return n;
}
Dev mntloopdevtab = { /* known to mntattach */
'~',
"mntloop",
devreset,
devinit,
devshutdown,
mntloopattach,
mntloopwalk,
mntloopstat,
mntloopopen,
devcreate,
mntloopclose,
mntloopread,
devbread,
mntloopwrite,
devbwrite,
devremove,
devwstat,
};