Add an fsatest test harness
diff --git a/Makefile b/Makefile
index 04c48be..3082c83 100644
--- a/Makefile
+++ b/Makefile
@@ -31,11 +31,14 @@
 
 SRCS=src/fsatrace.c src/$(PLAT)/proc.c src/$(PLAT)/shm.c $(OSSRCS)
 
-all: fsatrace$(EXE) lib
+all: fsatrace$(EXE) lib fsatest$(EXE) fsatest32$(EXE)
 
 fsatrace$(EXE): $(patsubst %.c,%.o,$(SRCS))
 	$(CC) $(LDFLAGS) $(LDOBJS) $^ $(LDLIBS) -o $@
 
+fsatest$(EXE): src/fsatest.o
+	$(CC) $^ -o $@
+
 dumpargs$(EXE): dumpargs.o
 	$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $@
 
diff --git a/src/fsatest.c b/src/fsatest.c
new file mode 100644
index 0000000..64c1c31
--- /dev/null
+++ b/src/fsatest.c
@@ -0,0 +1,74 @@
+
+
+/* Take a command line of options to perform
+   rfile -- file to read
+   wfile -- file to write
+   e[command] -- command to execute
+   f -- raise a failure
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+
+
+void unescape(char* s)
+{
+    for (int i = 0; s[i]; i++) {
+        if (s[i] != '#') continue;
+
+        if (s[i+1] != '#') {
+            s[i] = ' ';
+        } else {
+            memmove(&s[i], &s[i+1], strlen(&s[i+1]));
+            i++;
+        }
+    }
+}
+
+int main(int argc, const char* argv[])
+{
+    int trace = 0;
+    int exitCode = 0;
+    for (int i = 1; i < argc; i++) {
+        const char* s = argv[i];
+        FILE* fp;
+        char* cmdline;
+
+        switch (s[0]) {
+            case 'r':
+                if (trace) printf("Reading from: %s\n", &s[1]);
+                fp = fopen(&s[1], "r");
+                while(fgetc(fp) != EOF)
+                    ; // nothing
+                fclose(fp);
+                break;
+
+            case 'w':
+                if (trace) printf("Writing to: %s\n", &s[1]);
+                fp = fopen(&s[1], "w");
+                fputs("Written by fsatest harness\n", fp);
+                fclose(fp);
+                break;
+
+            case 'f':
+                if (trace) printf("Will return a failing exit code\n");
+                exitCode = 1;
+                break;
+
+            case 'e':
+                cmdline = strdup(&s[1]);
+                unescape(cmdline);
+                if (trace) printf("Running command: %s\n", cmdline);
+                system(cmdline);
+                free(cmdline);
+                break;
+
+            default:
+                printf("FAILED: Could not interpret command line: %s\n", s);
+                return 1;
+        }
+    }
+    return exitCode;
+}
diff --git a/unix.mk b/unix.mk
index 208b8a5..dece884 100644
--- a/unix.mk
+++ b/unix.mk
@@ -5,6 +5,9 @@
 %.os: %.c
 	$(CC) -c -fPIC $(CPPFLAGS) $(CFLAGS) $< -o $@
 
+fsatest32: fsatest
+	cp $^ $@
+
 fsatrace.so: $(patsubst %.c,%.os,$(SOSRCS))
 	$(CC) -shared $(LFLAGS) $^ -o $@ $(LDLIBS)
 
diff --git a/win.mk b/win.mk
index e4f33c2..d3dce2e 100644
--- a/win.mk
+++ b/win.mk
@@ -9,6 +9,7 @@
 LDLIBS=-lntdll -lpsapi
 
 lib: fsatrace32.dll fsatrace64.dll fsatracehelper.exe
+all: fsatest32.exe
 
 %32.o: %.c
 	$(CC32) -c $(CPPFLAGS32) $(CFLAGS) -march=i686 $< -o $@
@@ -16,6 +17,9 @@
 fsatracehelper.exe: $(HELPER_OBJ)
 	$(CC32) $< -o $@
 
+fsatest32.exe: src/fsatest32.o
+	$(CC32) $< -o $@
+
 fsatrace64.dll: $(OBJS64)
 	$(CC) -shared $(LDFLAGS64) $^ -o $@ $(LDLIBS)