ref: c7abd2e7be5f3f9aff60f18121d47da13e5b279d
dir: /src/execfs/execfs.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <bio.h>
#include <regexp.h>
typedef struct Xrule Xrule;
typedef struct Xfile Xfile;
struct Xrule
{
Reprog *re;
char *sub;
Xrule *next;
};
struct Xfile
{
char *path;
char *dest;
int fd;
};
Xrule *rules;
void
readrules(char *file)
{
Biobuf *bio;
char *s, *p, *d;
if((bio = Bopen(file, OREAD)) == nil)
sysfatal("open: %r");
while(s = Brdstr(bio, '\n', 1)){
Xrule *r;
p = s;
while(strchr("\t ", *p))
p++;
d = nil;
if(*p != '#'){
if(d = strchr(p, '\t'))
*d++ = 0;
else if(d = strchr(p, ' '))
*d++ = 0;
}
if(d == nil){
free(s);
continue;
}
while(strchr("\t ", *d))
d++;
r = emalloc9p(sizeof(*r));
if(r->re = regcomp(p)){
r->sub = estrdup9p(d);
r->next = rules;
rules = r;
} else {
fprint(2, "regcomp failed: %s\n", p);
free(r);
}
free(s);
}
Bterm(bio);
}
char*
matchrule(char *path)
{
Xrule *r;
Resub m[16];
char *s;
for(r = rules; r; r = r->next){
memset(m, 0, sizeof(m));
if(regexec(r->re, path, m, nelem(m))){
s = emalloc9p(1024);
regsub(r->sub, s, 1024, m, nelem(m));
return s;
}
}
return nil;
}
ulong
hash(char *s)
{
ulong h, t;
char c;
h = 0;
while(c = *s++){
t = h & 0xf8000000;
h <<= 5;
h ^= t>>27;
h ^= (ulong)c;
}
return h;
}
void
fsattach(Req *req)
{
Xfile *x;
if(req->ifcall.aname && req->ifcall.aname[0]){
respond(req, "invalid attach specifier");
return;
}
x = emalloc9p(sizeof(*x));
x->path = estrdup9p("");
x->dest = nil;
x->fd = -1;
req->fid->aux = x;
req->fid->qid.path = hash(x->path);
req->fid->qid.type = QTDIR;
req->fid->qid.vers = 0;
req->ofcall.qid = req->fid->qid;
respond(req, nil);
}
char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
Xfile *x;
char *p;
if(fid->qid.type != QTDIR)
return "walk in non-directory";
x = fid->aux;
if(strcmp(name, ".") == 0){
} else if(strcmp(name, "..") == 0){
if(p = strrchr(x->path, '/'))
*p = 0;
} else {
p = smprint("%s/%s", x->path, name);
free(x->path);
x->path = p;
}
fid->qid.path = hash(x->path);
if(x->dest = matchrule(x->path))
fid->qid.type = QTFILE;
else
fid->qid.type = QTDIR;
if(qid)
*qid = fid->qid;
return nil;
}
char*
fsclone(Fid *old, Fid *new)
{
Xfile *x;
x = emalloc9p(sizeof(*x));
memmove(x, old->aux, sizeof(*x));
if(x->path)
x->path = estrdup9p(x->path);
if(x->dest)
x->dest = estrdup9p(x->dest);
new->aux = x;
return nil;
}
void
fsstat(Req *req)
{
Xfile *x;
char *p;
Dir *d;
x = req->fid->aux;
d = &req->d;
memset(d, 0, sizeof(*d));
d->uid = estrdup9p("execfs");
d->gid = estrdup9p("execfs");
d->atime = d->mtime = time(0);
if(p = strrchr(x->path, '/'))
d->name = estrdup9p(p+1);
else
d->name = estrdup9p("/");
if(x->dest){
d->qid.type = QTFILE;
d->mode = 0444;
}else {
d->qid.type = QTDIR;
d->mode = DMDIR|0555;
}
respond(req, nil);
}
void
fsread(Req *req)
{
int n, pfd[2];
Xfile *x;
Srv *srv;
x = req->fid->aux;
if(x->dest == nil){
req->ofcall.count = 0;
respond(req, nil);
return;
}
if(x->fd < 0){
if(pipe(pfd) < 0){
responderror(req);
return;
}
if(rfork(RFPROC|RFNOWAIT|RFFDG|RFREND) == 0){
char *argv[4];
int i;
argv[0] = "rc";
argv[1] = "-c";
argv[2] = x->dest;
argv[3] = nil;
close(0);
open("/dev/null", OREAD);
dup(pfd[1], 1);
dup(pfd[1], 2);
for(i=3; i<20; i++)
close(i);
exec("/bin/rc", argv);
exits("exec");
}
x->fd = pfd[0];
close(pfd[1]);
}
srvrelease(srv = req->srv);
if((n = read(x->fd, req->ofcall.data, req->ifcall.count)) < 0)
responderror(req);
else {
req->ofcall.count = n;
respond(req, nil);
}
srvacquire(srv);
}
void
fsclunk(Fid *fid)
{
Xfile *x;
if(x = fid->aux){
fid->aux = nil;
if(x->fd >= 0)
close(x->fd);
free(x->path);
free(x->dest);
free(x);
}
}
Srv fs = {
.attach = fsattach,
.stat = fsstat,
.read = fsread,
.walk1 = fswalk1,
.clone = fsclone,
.destroyfid = fsclunk,
};
void
usage(void)
{
fprint(2, "usage: %s [-D] [-m mtpt] [-s srv] rulefile\n", argv0);
exits("usage");
}
void
main(int argc, char *argv[])
{
char *srv, *mtpt;
srv = nil;
mtpt = "/n/execfs";
ARGBEGIN {
case 'D':
chatty9p++;
break;
case 'm':
mtpt = EARGF(usage());
break;
case 's':
srv = EARGF(usage());
break;
default:
usage();
} ARGEND;
if(argc != 1)
usage();
readrules(*argv);
postmountsrv(&fs, srv, mtpt, MREPL);
}