writing modules made more easy
diff --git a/BUGS b/BUGS
index cd56648..0c1fb6c 100644
--- a/BUGS
+++ b/BUGS
@@ -5,3 +5,7 @@
 
 - I want really low priority for my cached pages.  Can they start out
   'old' so they will be thrown out on the first oportunity?
+
+- File size change could cause some strange behavior WRT the page
+  cache.
+
diff --git a/example/.cvsignore b/example/.cvsignore
index 94a32e3..e4188bc 100644
--- a/example/.cvsignore
+++ b/example/.cvsignore
@@ -3,3 +3,4 @@
 .deps
 fusexmp
 null
+hello
diff --git a/example/Makefile.am b/example/Makefile.am
index 19a3c32..a3880fa 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1,8 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
-noinst_PROGRAMS = fusexmp null
+noinst_PROGRAMS = fusexmp null hello
 
 fusexmp_SOURCES = fusexmp.c
 null_SOURCES = null.c
+hello_SOURCES = hello.c
 
 LDADD = ../lib/libfuse.a -lpthread
diff --git a/example/fusexmp.c b/example/fusexmp.c
index dc2a569..b9df79c 100644
--- a/example/fusexmp.c
+++ b/example/fusexmp.c
@@ -11,18 +11,12 @@
 #define _XOPEN_SOURCE 500
 #endif
 
-/* For setgroups() */
-#define _BSD_SOURCE
-
 #include <fuse.h>
 #include <stdio.h>
-#include <stdlib.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <dirent.h>
 #include <errno.h>
-#include <signal.h>
-#include <utime.h>
-#include <fcntl.h>
 
 static int xmp_getattr(const char *path, struct stat *stbuf)
 {
@@ -237,7 +231,6 @@
     return res;
 }
 
-
 static struct fuse_operations xmp_oper = {
     getattr:	xmp_getattr,
     readlink:	xmp_readlink,
@@ -258,93 +251,8 @@
     write:	xmp_write,
 };
 
-static void cleanup()
-{
-    close(0);
-    system(getenv("FUSE_UNMOUNT_CMD"));
-}
-
-static void exit_handler()
-{
-    exit(0);
-}
-
-static void set_signal_handlers()
-{
-    struct sigaction sa;
-
-    sa.sa_handler = exit_handler;
-    sigemptyset(&(sa.sa_mask));
-    sa.sa_flags = 0;
-
-    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
-	sigaction(SIGINT, &sa, NULL) == -1 || 
-	sigaction(SIGTERM, &sa, NULL) == -1) {
-	
-	perror("Cannot set exit signal handlers");
-        exit(1);
-    }
-
-    sa.sa_handler = SIG_IGN;
-    
-    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
-	perror("Cannot set ignored signals");
-        exit(1);
-    }
-}
-
 int main(int argc, char *argv[])
 {
-    int argctr;
-    int flags;
-    int multithreaded;
-    struct fuse *fuse;
-
-    argctr = 1;
-
-    atexit(cleanup);
-    set_signal_handlers();
-
-    flags = 0;
-    multithreaded = 1;
-    for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
-        switch(argv[argctr][1]) {
-        case 'd':
-            flags |= FUSE_DEBUG;
-            break;
-
-        case 's':
-            multithreaded = 0;
-            break;
-
-        case 'h':
-            fprintf(stderr,
-                    "usage: %s [options] \n"
-                    "Options:\n"
-                    "    -d      enable debug output\n"
-                    "    -s      disable multithreaded operation\n"
-                    "    -h      print help\n",
-                    argv[0]);
-            exit(1);
-            break;
-            
-        default:
-            fprintf(stderr, "invalid option: %s\n", argv[argctr]);
-            exit(1);
-        }
-    }
-    if(argctr != argc) {
-        fprintf(stderr, "missing or surplus argument\n");
-        exit(1);
-    }
-
-    fuse = fuse_new(0, flags);
-    fuse_set_operations(fuse, &xmp_oper);
-
-    if(multithreaded)
-        fuse_loop_mt(fuse);
-    else
-        fuse_loop(fuse);
-
+    fuse_main(argc, argv, &xmp_oper);
     return 0;
 }
diff --git a/example/hello.c b/example/hello.c
new file mode 100644
index 0000000..5cf75f4
--- /dev/null
+++ b/example/hello.c
@@ -0,0 +1,92 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include <fuse.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+
+static const char *hello_str = "Hello World!\n";
+
+static int hello_getattr(const char *path, struct stat *stbuf)
+{
+    int res = 0;
+
+    memset(stbuf, 0, sizeof(struct stat));
+    if(strcmp(path, "/") == 0) {
+        stbuf->st_mode = S_IFDIR | 0755;
+        stbuf->st_nlink = 2;
+    }
+    else if(strcmp(path, "/hello") == 0) {
+        stbuf->st_mode = S_IFREG | 0644;
+        stbuf->st_nlink = 1;
+        stbuf->st_size = strlen(hello_str);
+    }
+    else
+        res = -ENOENT;
+
+    return res;
+}
+
+static int hello_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
+{
+    if(strcmp(path, "/") != 0)
+        return -ENOENT;
+
+    filler(h, ".", 0);
+    filler(h, "..", 0);
+    filler(h, "hello", 0);
+
+    return 0;
+}
+
+static int hello_open(const char *path, int flags)
+{
+    if(strcmp(path, "/hello") != 0)
+        return -ENOENT;
+
+    if((flags & 3) != O_RDONLY)
+        return -EACCES;
+
+    return 0;
+}
+
+static int hello_read(const char *path, char *buf, size_t size, off_t offset)
+{
+    if(strcmp(path, "/hello") != 0)
+        return -ENOENT;
+    
+    memcpy(buf, hello_str + offset, size);
+    return size;
+}
+
+static struct fuse_operations null_oper = {
+    getattr:	hello_getattr,
+    readlink:	NULL,
+    getdir:     hello_getdir,
+    mknod:	NULL,
+    mkdir:	NULL,
+    symlink:	NULL,
+    unlink:	NULL,
+    rmdir:	NULL,
+    rename:     NULL,
+    link:	NULL,
+    chmod:	NULL,
+    chown:	NULL,
+    truncate:	NULL,
+    utime:	NULL,
+    open:	hello_open,
+    read:	hello_read,
+    write:	NULL,
+};
+
+int main(int argc, char *argv[])
+{
+    fuse_main(argc, argv, &null_oper);
+    return 0;
+}
diff --git a/example/null.c b/example/null.c
index c9816f1..7be4ab4 100644
--- a/example/null.c
+++ b/example/null.c
@@ -7,13 +7,10 @@
 */
 
 #include <fuse.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
+
 #include <unistd.h>
-#include <signal.h>
 #include <time.h>
+#include <errno.h>
 
 #define UNUSED __attribute__((unused))
 
@@ -88,93 +85,8 @@
     write:	null_write,
 };
 
-static void cleanup()
-{
-    close(0);
-    system(getenv("FUSE_UNMOUNT_CMD"));
-}
-
-static void exit_handler()
-{
-    exit(0);
-}
-
-static void set_signal_handlers()
-{
-    struct sigaction sa;
-
-    sa.sa_handler = exit_handler;
-    sigemptyset(&(sa.sa_mask));
-    sa.sa_flags = 0;
-
-    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
-	sigaction(SIGINT, &sa, NULL) == -1 || 
-	sigaction(SIGTERM, &sa, NULL) == -1) {
-	
-	perror("Cannot set exit signal handlers");
-        exit(1);
-    }
-
-    sa.sa_handler = SIG_IGN;
-    
-    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
-	perror("Cannot set ignored signals");
-        exit(1);
-    }
-}
-
 int main(int argc, char *argv[])
 {
-    int argctr;
-    int flags;
-    int multithreaded;
-    struct fuse *fuse;
-
-    argctr = 1;
-
-    atexit(cleanup);
-    set_signal_handlers();
-
-    flags = 0;
-    multithreaded = 1;
-    for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
-        switch(argv[argctr][1]) {
-        case 'd':
-            flags |= FUSE_DEBUG;
-            break;
-
-        case 's':
-            multithreaded = 0;
-            break;
-
-        case 'h':
-            fprintf(stderr,
-                    "usage: %s [options] \n"
-                    "Options:\n"
-                    "    -d      enable debug output\n"
-                    "    -s      disable multithreaded operation\n"
-                    "    -h      print help\n",
-                    argv[0]);
-            exit(1);
-            break;
-
-        default:
-            fprintf(stderr, "invalid option: %s\n", argv[argctr]);
-            exit(1);
-        }
-    }
-    if(argctr != argc) {
-        fprintf(stderr, "missing or surplus argument\n");
-        exit(1);
-    }
-
-    fuse = fuse_new(0, flags);
-    fuse_set_operations(fuse, &null_oper);
-
-    if(multithreaded)
-        fuse_loop_mt(fuse);
-    else
-        fuse_loop(fuse);
-
+    fuse_main(argc, argv, &null_oper);
     return 0;
 }
diff --git a/include/fuse.h b/include/fuse.h
index abdb45b..42ef8bb 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -12,6 +12,10 @@
 #include <sys/stat.h>
 #include <utime.h>
 
+/* ----------------------------------------------------------- *
+ * Basic FUSE API                                              *
+ * ----------------------------------------------------------- */
+
 /** Handle for a FUSE filesystem */
 struct fuse;
 
@@ -81,6 +85,7 @@
 /** Enable debuging output */
 #define FUSE_DEBUG       (1 << 1)
 
+
 /**
  * Create a new FUSE filesystem.
  *
@@ -108,6 +113,7 @@
  * operations are called. 
  *
  * @param f the FUSE handle
+ * @prarm op the file system operations
  */
 void fuse_loop(struct fuse *f);
 
@@ -134,6 +140,30 @@
  */
 void fuse_destroy(struct fuse *f);
 
+/* ----------------------------------------------------------- *
+ * Miscellaneous helper fuctions                               *
+ * ----------------------------------------------------------- */
+
+/*
+ * Main function of FUSE.
+ *
+ * This is for the lazy.  This is all that has to be called from the
+ * main() function.
+ * 
+ * This function does the following:
+ *   - mounts the filesystem
+ *   - installs signal handlers for INT, HUP, TERM and PIPE
+ *   - registers an exit handler to unmount the filesystem on program exit
+ *   - parses command line options (-d -s and -h)
+ *   - creates a fuse handle
+ *   - registers the operations
+ *   - calls either the single-threaded or the multi-threaded event loop
+ *
+ * @param argc the argument counter passed to the main() function
+ * @param argv the argument vector passed to the main() function
+ * @prarm op the file system operation 
+ */
+void fuse_main(int argc, char *argv[], const struct fuse_operations *op);
 
 /* ----------------------------------------------------------- *
  * Advanced API for event handling, don't worry about this...  *
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 7f289f7..5ecee0b 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -5,4 +5,5 @@
 libfuse_a_SOURCES = 	\
 	fuse.c		\
 	fuse_mt.c	\
+	helper.c	\
 	fuse_i.h
diff --git a/lib/fuse.c b/lib/fuse.c
index 4042993..c8bc3e4 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -17,6 +17,8 @@
 
 #define FUSE_MAX_PATH 4096
 
+#define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
+
 static struct node *__get_node(struct fuse *f, fino_t ino)
 {
     size_t hash = ino % f->ino_table_size;
@@ -891,7 +893,7 @@
     struct fuse *f;
     struct node *root;
     char verstr[128];
-    char *realver = getenv("FUSE_KERNEL_VERSION");
+    char *realver = getenv(FUSE_KERNEL_VERSION_ENV);
     
     if(realver != NULL) {
         sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
diff --git a/lib/helper.c b/lib/helper.c
new file mode 100644
index 0000000..f4a8a16
--- /dev/null
+++ b/lib/helper.c
@@ -0,0 +1,154 @@
+/*
+    FUSE: Filesystem in Userspace
+    Copyright (C) 2001  Miklos Szeredi (mszeredi@inf.bme.hu)
+
+    This program can be distributed under the terms of the GNU GPL.
+    See the file COPYING.
+*/
+
+#include "fuse.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <signal.h>
+#include <errno.h>
+
+#define FUSE_MOUNTED_ENV     "_FUSE_MOUNTED"
+#define FUSE_UMOUNT_CMD_ENV  "_FUSE_UNMOUNT_CMD"
+
+static void usage(char *progname)
+{
+    fprintf(stderr,
+            "usage: %s mountpoint [options] \n"
+            "Options:\n"
+            "    -d      enable debug output\n"
+            "    -s      disable multithreaded operation\n"
+            "    -h      print help\n",
+            progname);
+    exit(1);
+}
+
+static void fuse_unmount()
+{
+    close(0);
+    system(getenv(FUSE_UMOUNT_CMD_ENV));
+}
+
+static int fuse_mount(int *argcp, char **argv)
+{
+    char *isreexec = getenv(FUSE_MOUNTED_ENV);
+
+    if(isreexec == NULL) {
+        int i;
+        int argc = *argcp;
+        char *mountprog = "fusermount";
+        char **newargv = (char **) malloc((1 + argc + 1) * sizeof(char *));
+
+        if(argc < 2 || argv[1][0] == '-')
+            usage(argv[0]);
+        
+        /* oldargs: "PROG MOUNTPOINT ARGS..."
+           newargs: "fusermount MOUNTPOINT PROG ARGS..." */
+
+        newargv[0] = mountprog;
+        newargv[1] = argv[1];
+        newargv[2] = argv[0];
+        for(i = 2; i < argc; i++)
+            newargv[i+1] = argv[i];
+        newargv[i+1] = NULL;
+
+        execvp(mountprog, newargv);
+        fprintf(stderr, "fuse: failed to exec %s: %s\n", mountprog,
+                strerror(errno));
+        return -1;
+    }
+    unsetenv(FUSE_MOUNTED_ENV);
+    
+    /* The actual file descriptor is stdin */
+    return 0;
+}
+
+
+static void exit_handler()
+{
+    exit(0);
+}
+
+static void set_signal_handlers()
+{
+    struct sigaction sa;
+
+    sa.sa_handler = exit_handler;
+    sigemptyset(&(sa.sa_mask));
+    sa.sa_flags = 0;
+
+    if (sigaction(SIGHUP, &sa, NULL) == -1 || 
+	sigaction(SIGINT, &sa, NULL) == -1 || 
+	sigaction(SIGTERM, &sa, NULL) == -1) {
+	
+	perror("Cannot set exit signal handlers");
+        exit(1);
+    }
+
+    sa.sa_handler = SIG_IGN;
+    
+    if(sigaction(SIGPIPE, &sa, NULL) == -1) {
+	perror("Cannot set ignored signals");
+        exit(1);
+    }
+}
+
+void fuse_main(int argc, char *argv[], const struct fuse_operations *op)
+{
+    int fd;
+    int argctr;
+    int flags;
+    int multithreaded;
+    struct fuse *fuse;
+
+    fd = fuse_mount(&argc, argv);
+    if(fd == -1)
+        exit(1);
+
+    atexit(fuse_unmount);
+    set_signal_handlers();
+
+    argctr = 1;
+    flags = 0;
+    multithreaded = 1;
+    for(; argctr < argc && argv[argctr][0] == '-'; argctr ++) {
+        switch(argv[argctr][1]) {
+        case 'd':
+            flags |= FUSE_DEBUG;
+            break;
+
+        case 's':
+            multithreaded = 0;
+            break;
+
+        case 'h':
+            usage(argv[0]);
+            break;
+
+        default:
+            fprintf(stderr, "invalid option: %s\n", argv[argctr]);
+            exit(1);
+        }
+    }
+    if(argctr != argc) {
+        fprintf(stderr, "missing or surplus argument\n");
+        exit(1);
+    }
+
+    fuse = fuse_new(fd, flags);
+    fuse_set_operations(fuse, op);
+
+    if(multithreaded)
+        fuse_loop_mt(fuse);
+    else
+        fuse_loop(fuse);
+}
+
diff --git a/util/fusermount.c b/util/fusermount.c
index 0e256e5..ee51269 100644
--- a/util/fusermount.c
+++ b/util/fusermount.c
@@ -39,6 +39,10 @@
 
 #define FUSE_DEV "/proc/fs/fuse/dev"
 
+#define FUSE_MOUNTED_ENV        "_FUSE_MOUNTED"
+#define FUSE_UMOUNT_CMD_ENV     "_FUSE_UNMOUNT_CMD"
+#define FUSE_KERNEL_VERSION_ENV "_FUSE_KERNEL_VERSION"
+
 const char *progname;
 
 static const char *get_user_name()
@@ -497,9 +501,10 @@
 
     unmount_cmd = (char *) malloc(strlen(mypath) + strlen(mnt) + 64);
     sprintf(unmount_cmd, "%s -u %s", mypath, mnt);
-    setenv("FUSE_UNMOUNT_CMD", unmount_cmd, 1);
+    setenv(FUSE_UMOUNT_CMD_ENV, unmount_cmd, 1);
     sprintf(verstr, "%i", FUSE_KERNEL_VERSION);
-    setenv("FUSE_KERNEL_VERSION", verstr, 1);
+    setenv(FUSE_KERNEL_VERSION_ENV, verstr, 1);
+    setenv(FUSE_MOUNTED_ENV, "", 1);
 
     execvp(userprog[0], userprog);
     fprintf(stderr, "%s: failed to exec %s: %s\n", progname, userprog[0],