<?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:webmaster@plan9.bell-labs.com">webmaster@plan9.bell-labs.com</a>.</span>
</font></center>
</body>
</html>