<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/maht/actionfs.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/maht/actionfs.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
// Put

//      8c -w actionfs.c &amp;&amp;  8l actionfs.8  &amp;&amp; mv 8.out /usr/maht/bin/386/actionfs


#include &lt;u.h&gt;
#include &lt;libc.h&gt;
#include &lt;fcall.h&gt;
#include &lt;thread.h&gt;
#include &lt;9p.h&gt;
#include &lt;regexp.h&gt;
#include &lt;stdio.h&gt;

typedef struct Path Path;
struct Path
{
       Qid qid;
       char *name;
       Path *next;
};

Reprog  *freg;
Path *root = nil;
int nmatches;
int client = 0;

static void
fsattach(Req *r)
{
       r-&gt;ofcall.qid = (Qid){0, ++client, QTDIR};
       r-&gt;fid-&gt;qid = r-&gt;ofcall.qid;
       respond(r, nil);
}

static void
print_qid(Qid *q) {
       print("p %x v %d f %x\n", q-&gt;path, q-&gt;vers, q-&gt;type);
}

static void
print_matches(Resub *matches) {
       if(!matches) {
               print("No match\n");
               return;
       }

       char *bit;
       int i, k;
       for(i = 0; i &lt; nmatches; i++) {
               k = (matches[i].ep - matches[i].sp) + 1;
               bit = (char*)malloc(k);
               strecpy(bit, bit + k, matches[i].sp);
               free(bit);
       }
       print("\n");
}

static void
print_path(Path *p) {
       print("Name: %s\n", p-&gt;name);
       print_qid(&amp;p-&gt;qid);
       print("Next: %x\n", p-&gt;next);
}

static Resub*
re(char *txt) {
       Resub* matches = (Resub*)calloc(nmatches, sizeof(Resub));
       if(regexec(freg, txt, matches, nmatches))
               return matches;
       free(matches);
       return nil;
}

static Path*
find_path(Qid *qid) {
       Path *p;
       for(p = root; p; p = p-&gt;next)
               if(qid-&gt;path == p-&gt;qid.path)
                       break;
       return p;
}

static Path*
find_prev_path(Qid *qid) {
       Path *p;
       for(p = root; p; p = p-&gt;next) {
               if(p-&gt;next &amp;&amp; (qid-&gt;path == p-&gt;next-&gt;qid.path))
                       break;
       }
       return p;
}

static Qid*
find_qid(char *name) {
       Path *p;
       Resub *m;
       for(p = root; p; p = p-&gt;next)
               if(strcmp(name, p-&gt;name) == 0)
                       return &amp;p-&gt;qid;
       if(!(m = re(name)))
               return nil;
       free(m);

       p = (Path*)mallocz(sizeof(Path), 1);
       p-&gt;qid.path = root ? root-&gt;qid.path +1 : 1;
       p-&gt;qid.vers = 0;
       p-&gt;next = root;
       p-&gt;name = strdup(name);
       root = p;
       return &amp;root-&gt;qid;
}

static char*
fswalk1(Fid *fid, char *name, Qid *qid)
{
       Qid *q;

       if(!(q = find_qid(name)))
               return "Not Found";

       q-&gt;vers++;
       memcpy(qid, q, sizeof(Qid));
       memcpy(&amp;fid-&gt;qid, q, sizeof(Qid));

       return nil;
}

static void
fsstat(Req *r)
{
       Path *p;
       Dir *d = &amp;r-&gt;d;
       memset(d, 0, sizeof *d);
       d-&gt;uid = strdup("inband");
       d-&gt;gid = strdup("inband");

       p = find_path(&amp;r-&gt;fid-&gt;qid);
       d-&gt;name = strdup(p-&gt;name);
       d-&gt;mode = 0444;
       memcpy(&amp;d-&gt;qid, &amp;(r-&gt;fid-&gt;qid), sizeof(Qid));
       d-&gt;length = 0;
       respond(r, nil);
}

char **
build_argv(int fd, char *name) {
       char **argv = malloc(sizeof(char*) * (nmatches + 3));
       if(fd &gt; 0)
               argv[0] = smprint("action-read");
       else
               argv[0] = smprint("action-write");

       argv[1] = smprint("%d", abs(fd));

       Resub *matches = re(name);
       int i, j, k;
       for(i = 0, j = 2; i &lt; nmatches; i++, j++) {
               k = (matches[i].ep - matches[i].sp) + 1;
               argv[j] = (char*)mallocz(k + 1, 1);
               strecpy(argv[j], argv[j] + k, matches[i].sp);
       }
       argv[j] = nil;

       return argv;
}

static char *
do_action(char *action, int fd, Path *p) {
       char **argv = build_argv(fd, p-&gt;name);
       char *error = nil;
       int i;

       switch(fork()) {
       case 0 :
               exec(action, argv);
               error = "exec failed";
               break;
       case -1 :
               error = "fork failed";
               break;
       default :
               wait();
               for(i = 0; i &lt; nmatches+2; i++)
                       free(argv[i]);
               free(argv);
               break;
       }

       return error;
}

static void
fsopen(Req *r)
{
       int fd;
       switch(r-&gt;ifcall.mode &amp; 1) { // discard OTRUNC etc.
       case OREAD :
               fd = create(tmpnam(nil), ORDWR|ORCLOSE, 0600);
               if(fd &lt; 1)  { // assume fd 0 is taken !
                       respond(r, "/tmp/$file create failed");
                       return;
               }
               break;
       case OWRITE :
               fd = create(tmpnam(nil), ORDWR|ORCLOSE, 0600);
               if(fd &lt; 1)  { // assume fd 0 is taken !
                       respond(r, "/tmp/$file create failed");
                       return;
               }
               fd = -fd;
               break;
       default :
               respond(r, "permission denied");
               return;
       }

       r-&gt;fid-&gt;aux = (void*)fd;


       Path *p = find_path(&amp;r-&gt;fid-&gt;qid);
       char *error = nil;
       if(fd &gt; 0)
               error = do_action("/bin/action-read", fd, p);
       respond(r, error);
}

static void
remove_path(Path *p) {
       Path *pp;
       pp = find_prev_path(&amp;p-&gt;qid);
       if(pp)
               pp-&gt;next = p-&gt;next;
       else
               root = nil;
       free(p-&gt;name);
       free(p);
}

static void
fsclose(Fid *fid) {

       if(fid-&gt;aux)
               close(abs((int)fid-&gt;aux));

       Path *p = find_path(&amp;fid-&gt;qid);
       if(p &amp;&amp; p-&gt;qid.path)  // p *should* always be non null
               if(--p-&gt;qid.vers == 0)
                       remove_path(p);
}

static void
fsclunk(Fid *fid) {
       Path *p = find_path(&amp;fid-&gt;qid);

       if((int)fid-&gt;aux &lt; 0) {
               seek(abs((int)fid-&gt;aux), 0, 0);
               do_action("/bin/action-write", (int)fid-&gt;aux, p);
       }
       if(fid-&gt;aux)
               close(abs((int)fid-&gt;aux));

       if(p &amp;&amp; p-&gt;qid.path)  // p *should* always be non null
               if(--p-&gt;qid.vers == 0)
                       remove_path(p);
}

static void
fsread(Req *r)
{
       seek((int)r-&gt;fid-&gt;aux, r-&gt;ifcall.offset, 0);
       int k = read((int)r-&gt;fid-&gt;aux, r-&gt;ofcall.data, r-&gt;ifcall.count);
       if(k &lt; 0)
               respond(r, "Read failed");
       r-&gt;ofcall.count = k;
       respond(r, nil);
}

static void
fswrite(Req *r)
{
       seek(abs((int)r-&gt;fid-&gt;aux), r-&gt;ifcall.offset, 0);
       int k = write(abs((int)r-&gt;fid-&gt;aux), r-&gt;ifcall.data, r-&gt;ifcall.count);
       if(k &lt; 0)
               respond(r, "Write failed");
       r-&gt;ofcall.count = k;
       respond(r, nil);
}

Srv numsrv = {
attach= fsattach,
walk1=  fswalk1,
open=   fsopen,
read=   fsread,
write=  fswrite,
stat=   fsstat,
destroyfid = fsclunk,
};

static int
num_matches(char *txt){
       int i = 0;
       char *p;
       for(p = txt; p ; i++) {
               p = strchr(p, '(');
               if(p) p++;
       }
       return i ? i : 1;
}

extern int chatty9p;

void
main(int argc, char **argv)
{
       char *mtpt, *service;
       char *reg;

       ARGBEGIN{
       case 'D':
               chatty9p++;
               break;
       }ARGEND

       if(argc == 1)
               reg = argv[0];
       else
               reg = ".*";

       nmatches = num_matches(reg);
       freg = regcomp(reg);

       mtpt = "/n/actionfs";
       service = "actionfs";

       chdir("/tmp");
       postmountsrv(&amp;numsrv, service, mtpt, MREPL);
       exits(nil);
}
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>