Add a FUSE implementation for afsd
authorAndrew Deason <adeason@sinenomine.net>
Thu, 8 Apr 2010 19:50:18 +0000 (14:50 -0500)
committerDerrick Brashear <shadow@dementia.org>
Wed, 14 Apr 2010 22:17:27 +0000 (15:17 -0700)
This adds afsd.fuse, which allows for mounting AFS via FUSE (via
libuafs), instead of via the OpenAFS kernel module.

Change-Id: Iaafe4a5f3034fed943e2e73f79ac95580946f9a8
Reviewed-on: http://gerrit.openafs.org/1725
Tested-by: Andrew Deason <adeason@sinenomine.net>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

Makefile.in
acinclude.m4
src/LICENSE
src/afs/UKERNEL/afs_usrops.h
src/afsd/Makefile.in
src/afsd/afsd_fuse.c [new file with mode: 0644]
src/cf/fuse.m4 [new file with mode: 0644]

index 798dc48..d0ef3be 100644 (file)
@@ -308,7 +308,7 @@ venus: cmd comerr volser ptserver
        +${COMPILE_PART1} venus ${COMPILE_PART2}
        +${COMPILE_PART1} venus/test ${COMPILE_PART2}
 
-afsd: cmd comerr sys kauth
+afsd: cmd comerr sys kauth @CLIENT_UAFS_DEP@
        +${COMPILE_PART1} afsd ${COMPILE_PART2}
 
 gtx: cmd comerr auth kauth
index e2eb9c5..80cb33a 100644 (file)
@@ -1524,6 +1524,7 @@ AC_SUBST(XSLTPROC)
 
 OPENAFS_OSCONF
 OPENAFS_KRB5CONF
+OPENAFS_FUSE
 
 TOP_SRCDIR="${srcdir}/src"
 dnl
index 36a54eb..c71bb0a 100644 (file)
    more than one year after the cause of action arose. Each party waives
    its rights to a jury trial in any resulting litigation.
 
-Kerberos 5 ticket support in rxkad is subject to the following copyright:
-/*
- * Copyright (c) 1995, 1996, 1997, 2002 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * All rights reserved.
- * 
+OpenAFS contains code licensed under a standard 3-term BSD license with
+the following names as copyright holders:
+
+Kungliga Tekniska Högskolan (Royal Institute of Technology, Stockholm, Sweden)
+Sine Nomine Associates
+
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
- * 
+ *
  * 1. Redistributions of source code must retain the above copyright
  *    notice, this list of conditions and the following disclaimer.
- * 
+ *
  * 2. Redistributions in binary form must reproduce the above copyright
  *    notice, this list of conditions and the following disclaimer in the
  *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
  * 
- * 3. Neither the name of the Institute nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 Some code in rxkad/ticket5.c is subject to the following copyright:
 /*
index c3c8c20..1ca506e 100644 (file)
@@ -149,5 +149,6 @@ extern int uafs_statmountpoint_r(char *path);
 extern int uafs_statvfs(struct statvfs *buf);
 extern void uafs_Shutdown(void);
 extern void uafs_mount(void);
+extern int uafs_fork(int wait, void* (*cbf) (void *), void *rock);
 
 #endif /* __AFS_USROPS_H__ */
index d1c2d71..7511cfa 100644 (file)
@@ -18,17 +18,24 @@ LDFLAGS = ${XLDFLAGS} ${ARCHFLAGS}
 #
 # What to make
 #
-all: afsd vsys
+all: afsd vsys @ENABLE_FUSE_CLIENT@
 
 #
 # Programs
 #
 
 AFSLIBS=${TOP_LIBDIR}/libauth.a ${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/libsys.a ${TOP_LIBDIR}/util.a ${TOP_LIBDIR}/librx.a ${TOP_LIBDIR}/liblwp.a ${TOP_LIBDIR}/util.a
+UAFSLIBS=${TOP_LIBDIR}/libuafs.a ${TOP_LIBDIR}/libdes.a ${TOP_LIBDIR}/libafsutil.a ${TOP_LIBDIR}/libcmd.a ${TOP_LIBDIR}/libafsutil.a
+
+UAFS_CFLAGS=${CFLAGS} -I${TOP_SRCDIR}/afs -I${TOP_SRCDIR}/afs/UKERNEL -I${TOP_SRCDIR}/rx/UKERNEL -DUKERNEL @FUSE_CFLAGS@
+UAFS_XLIBS=${XLIBS} @FUSE_LIBS@
 
 afsd: afsd.o afsd_kernel.o $(AFSLIBS) $(AFSD_LIBS)
        ${CC} ${CFLAGS} -o afsd afsd.o afsd_kernel.o $(NON_SHARED) $(LDFLAGS) $(AFSD_LDFLAGS) $(AFSLIBS) ${XLIBS} ${AFSD_LIBS}
 
+afsd.fuse: afsd_fuse.o $(UAFSLIBS) $(AFSD_LIBS)
+       ${CC} ${UAFS_CFLAGS} -o afsd.fuse afsd_fuse.o $(NON_SHARED) $(LDFLAGS) $(AFSD_LDFLAGS) $(UAFSLIBS) ${UAFS_XLIBS} ${AFSD_LIBS}
+
 vsys: vsys.o
        ${CC} ${CFLAGS} -o vsys vsys.o ${TOP_LIBDIR}/libsys.a $(LDFLAGS) ${XLIBS}
 
@@ -41,10 +48,13 @@ afsd.o: afsd.c AFS_component_version_number.c
 afsd_kernel.o: afsd_kernel.c
        $(CC) $(CFLAGS) @CFLAGS_NOERROR@ -c $<
 
+afsd_fuse.o: afsd_fuse.c AFS_component_version_number.c
+       ${CC} -c ${CPPFLAGS} ${UAFS_CFLAGS} afsd_fuse.c -o afsd_fuse.o
+
 vsys.o: vsys.c AFS_component_version_number.c
 
 clean:
-       $(RM) -f *.o vsys afsd core AFS_component_version_number.c
+       $(RM) -f *.o vsys afsd afsd.fuse core AFS_component_version_number.c
 
 system: install
 
diff --git a/src/afsd/afsd_fuse.c b/src/afsd/afsd_fuse.c
new file mode 100644 (file)
index 0000000..4e6cc5c
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * Copyright (c) 2008-2010 Sine Nomine Associates
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of Sine Nomine Associates nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
+ * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * afsd_fuse.c - Driver for afsd.fuse, and glue between FUSE and libuafs
+ */
+
+#include <afsconfig.h>
+#include <afs/param.h>
+
+#include <sysincludes.h>
+#include <afs/afsutil.h>
+#include <afs_usrops.h>
+#include <afs/cmd.h>
+#include <afs/afs_args.h>
+
+#include "afsd.h"
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#define FUSE_USE_VERSION 27
+#include <fuse.h>
+
+/* command-line arguments to pass to afsd and the cmd_ library */
+static struct fuse_args afsd_args = FUSE_ARGS_INIT(0, NULL);
+
+/* command-line arguments to pass to FUSE */
+static struct fuse_args fuse_args = FUSE_ARGS_INIT(0, NULL);
+
+/* used for command-line parsing in fuafsd_fuse_opt below */
+static int fuafsd_cmd_accept = 0;
+static int nullfd;
+static int stderr_save;
+
+/**
+ * Turn FUSE-y paths into libuafs-y paths.
+ *
+ * @param[in] apath  a path in the form of /localcell/foo/bar
+ *
+ * @return a path (non-const) in the form /afs/localcell/foo/bar to be freed
+ *         by the caller
+ */
+static char *
+afs_path(const char *apath)
+{
+    size_t len;
+    static const char prefix[] = "/afs/";
+    char *path;
+
+    len = strlen(apath) + sizeof(prefix);
+
+    path = malloc(len);
+
+    sprintf(path, "%s%s", prefix, apath);
+
+    return path;
+}
+
+static void *
+fuafsd_init(struct fuse_conn_info *conn)
+{
+    uafs_Run();
+    return NULL;
+}
+
+/* Wrappers around libuafs calls for FUSE */
+
+static int
+fuafsd_getattr(const char *apath, struct stat *stbuf)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_lstat(path, stbuf);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_opendir(const char *apath, struct fuse_file_info * fi)
+{
+       usr_DIR * dirp;
+       char *path = afs_path(apath);
+
+       dirp = uafs_opendir(path);
+
+       free(path);
+
+       if (!dirp) {
+               return -errno;
+       }
+
+       fi->fh = (uintptr_t)dirp;
+
+       return 0;
+}
+
+static int
+fuafsd_readdir(const char *path, void * buf, fuse_fill_dir_t filler,
+               off_t offset, struct fuse_file_info * fi)
+{
+       usr_DIR * dirp;
+       struct usr_dirent * direntP;
+
+       dirp = (usr_DIR *)(uintptr_t)fi->fh;
+
+       errno = 0;
+       while ((direntP = uafs_readdir(dirp))) {
+               if (filler(buf, direntP->d_name, NULL, 0)) {
+                       /* buffer is full */
+                       return 0;
+               }
+       }
+
+       return -errno;
+}
+
+static int
+fuafsd_releasedir(const char *path, struct fuse_file_info * fi)
+{
+       return uafs_closedir((usr_DIR *)(uintptr_t)fi->fh);
+}
+
+static int
+fuafsd_create(const char *apath, mode_t mode, struct fuse_file_info * fi)
+{
+       int fd;
+       char *path = afs_path(apath);
+
+       fd = uafs_open(path, fi->flags, mode);
+
+       free(path);
+
+       if (fd < 0) {
+               return -errno;
+       }
+
+       fi->fh = fd;
+
+       return 0;
+}
+
+static int
+fuafsd_open(const char *path, struct fuse_file_info * fi)
+{
+       return fuafsd_create(path, 0, fi);
+}
+
+static int
+fuafsd_read(const char *path, char * buf, size_t len, off_t offset,
+       struct fuse_file_info * fi)
+{
+       int fd, code;
+
+       fd = fi->fh;
+
+       code = uafs_pread(fd, buf, len, offset);
+       if (code < 0) {
+               return -errno;
+       }
+
+       return code;
+}
+
+static int
+fuafsd_readlink(const char *apath, char * buf, size_t len)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_readlink(path, buf, len);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+
+       buf[code] = '\0';
+
+       return 0;
+}
+
+static int
+fuafsd_mkdir(const char *apath, mode_t mode)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_mkdir(path, mode);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_unlink(const char *apath)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_unlink(path);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_rmdir(const char *apath)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_rmdir(path);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_symlink(const char *atarget, const char *asource)
+{
+       int code;
+       char *target = afs_path(atarget);
+       char *source = afs_path(asource);
+
+       code = uafs_symlink(target, source);
+
+       free(target);
+       free(source);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_rename(const char *aold, const char *anew)
+{
+       int code;
+       char *old = afs_path(aold);
+       char *new = afs_path(anew);
+
+       code = uafs_rename(old, new);
+
+       free(old);
+       free(new);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_link(const char *aexisting, const char *anew)
+{
+       int code;
+       char *existing = afs_path(aexisting);
+       char *new = afs_path(anew);
+
+       code = uafs_link(existing, new);
+
+       free(existing);
+       free(new);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_chmod(const char *apath, mode_t mode)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_chmod(path, mode);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_truncate(const char *apath, off_t length)
+{
+       int code;
+       char *path = afs_path(apath);
+
+       code = uafs_truncate(path, length);
+
+       free(path);
+
+       if (code < 0) {
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+fuafsd_write(const char *path, const char *abuf, size_t len, off_t offset,
+             struct fuse_file_info * fi)
+{
+       int fd, code;
+       char *buf = malloc(len);
+
+       fd = fi->fh;
+       memcpy(buf, abuf, len);
+
+       code = uafs_pwrite(fd, buf, len, offset);
+
+       free(buf);
+
+       if (code < 0) {
+               return -errno;
+       }
+
+       return code;
+}
+
+static int
+fuafsd_statvfs(const char * path, struct statvfs * buf)
+{
+       if (uafs_statvfs(buf) < 0) {
+               return -errno;
+       }
+
+       /*
+        * FUSE ignores frsize, and uses bsize for displaying e.g. available
+        * space. Just set bsize to frsize so we get a consistent `df` output.
+        */
+       buf->f_bsize = buf->f_frsize;
+       return 0;
+}
+
+static int
+fuafsd_release(const char *path, struct fuse_file_info * fi)
+{
+       int fd;
+
+       fd = fi->fh;
+
+       if (uafs_close(fd) < 0) {
+               return -errno;
+       }
+
+       return 0;
+}
+
+static void
+fuafsd_destroy(void * private_data)
+{
+       uafs_Shutdown();
+}
+
+static struct fuse_operations fuafsd_oper = {
+       .init       = fuafsd_init,
+       .getattr    = fuafsd_getattr,
+       .opendir    = fuafsd_opendir,
+       .readdir    = fuafsd_readdir,
+       .releasedir = fuafsd_releasedir,
+       .open       = fuafsd_open,
+       .create     = fuafsd_create,
+       .read       = fuafsd_read,
+       .readlink   = fuafsd_readlink,
+       .mkdir      = fuafsd_mkdir,
+       .rmdir      = fuafsd_rmdir,
+       .link       = fuafsd_link,
+       .unlink     = fuafsd_unlink,
+       .symlink    = fuafsd_symlink,
+       .rename     = fuafsd_rename,
+       .chmod      = fuafsd_chmod,
+       .truncate   = fuafsd_truncate,
+       .write      = fuafsd_write,
+       .statfs     = fuafsd_statvfs,
+       .release    = fuafsd_release,
+       .destroy    = fuafsd_destroy
+};
+
+/* Command line argument processing */
+
+/*
+ * See fuafsd_fuse_opt below.
+ */
+static int
+fuafsd_cmd_check(struct cmd_syndesc * ts, void *beforeRock)
+{
+       fuafsd_cmd_accept = 1;
+       return 1;
+}
+
+/*
+ * Split arguments into FUSE and afsd/libcmd arguments. To determine whether an
+ * argument is meant for FUSE or for the cmd interface, we pass the given
+ * argument to cmd_Dispatch, and see if our beforeProc is run (which we set to
+ * fuafsd_cmd_check). If it was run, the argument is acceptable to cmd; if it
+ * was not run, cmd doesn't know what to do with the argument, so we assume the
+ * argument is meant for FUSE. We can tell if fuafsd_cmd_check was run by the
+ * global fuafsd_cmd_accept bool, which is set to true when fuafsd_cmd_check is
+ * run.
+ */
+static void
+split_args(const struct fuse_args *args)
+{
+       int i;
+
+       cmd_SetBeforeProc(fuafsd_cmd_check, NULL);
+
+       nullfd = open("/dev/null", O_WRONLY);
+       stderr_save = dup(2);
+       if (nullfd < 0 || stderr_save < 0) {
+               perror("open/dup");
+               exit(1);
+       }
+
+       for (i = 0; args->argv[i]; ++i) {
+               int code;
+               char *arg = args->argv[i];
+               char *argv[3] = {args->argv[0], arg, NULL};
+
+               if (fuafsd_cmd_accept) {
+                       fuse_opt_add_arg(&afsd_args, arg);
+                       fuafsd_cmd_accept = 0;
+                       continue;
+               }
+
+               /* redirect stderr to null, so libcmd doesn't print out
+                * an error message for unknown options */
+               if (dup2(nullfd, 2) < 0) {
+                       perror("dup2");
+                       exit(1);
+               }
+
+               code = cmd_Dispatch(2, argv);
+
+               if (dup2(stderr_save, 2) < 0) {
+                       perror("dup2");
+                       exit(1);
+               }
+
+               /* fuafsd_cmd_check should prevent the dispatch from succeeding;
+                * the only way we should be able to succeed is if -help was
+                * specified, so just exit */
+               if (code == 0) {
+                       exit(1);
+               }
+
+               if (fuafsd_cmd_accept || code == CMD_TOOFEW) {
+                       /* libcmd accepted the argument; must go to afsd */
+                       fuse_opt_add_arg(&afsd_args, arg);
+
+                       if (code == CMD_TOOFEW) {
+                               /* flag takes another argument; get the next one, too */
+                               fuafsd_cmd_accept = 1;
+                       } else {
+                               fuafsd_cmd_accept = 0;
+                       }
+
+               } else {
+                       /* libcmd doesn't recognize the argument; give it to FUSE */
+                       fuse_opt_add_arg(&fuse_args, arg);
+               }
+       }
+
+       if (close(nullfd) < 0) {
+               perror("close");
+       }
+       if (close(stderr_save) < 0) {
+               perror("close");
+       }
+
+       cmd_SetBeforeProc(NULL, NULL);
+}
+
+/*
+ * First we divide the given arguments into FUSE and cmd arguments, pass the
+ * FUSE arguments to FUSE, and call cmd_Dispatch in the FUSE init function.
+ */
+int
+main(int argc, char **argv)
+{
+       int code;
+       struct fuse_args args = FUSE_ARGS_INIT(argc-1, &argv[1]);
+       fuse_opt_add_arg(&afsd_args, argv[0]);
+       fuse_opt_add_arg(&fuse_args, argv[0]);
+
+       /* let us determine file inode numbers, not FUSE. also make "AFS" appear
+        * in df/mount/mnttab/etc output. */
+       fuse_opt_add_arg(&fuse_args, "-ouse_ino,fsname=AFS");
+
+       code = uafs_Setup("/afs");
+       if (code) {
+               errno = code;
+               perror("libuafs");
+               return 1;
+       }
+
+       split_args(&args);
+
+       uafs_ParseArgs(afsd_args.argc, afsd_args.argv);
+
+       /* pass "-- /mount/dir" to fuse to specify dir to mount; "--" is
+        * just to make sure fuse doesn't interpret the mount dir as a flag
+        */
+       fuse_opt_add_arg(&fuse_args, "--");
+       fuse_opt_add_arg(&fuse_args, uafs_MountDir());
+
+       return fuse_main(fuse_args.argc, fuse_args.argv, &fuafsd_oper, NULL);
+}
diff --git a/src/cf/fuse.m4 b/src/cf/fuse.m4
new file mode 100644 (file)
index 0000000..9b0ee6f
--- /dev/null
@@ -0,0 +1,25 @@
+dnl
+dnl $Id$
+dnl
+dnl FUSE autoconf glue
+dnl
+
+AC_DEFUN([OPENAFS_FUSE],[
+
+AC_ARG_ENABLE([fuse-client],
+    [AS_HELP_STRING([--enable-fuse-client],[enable building of the FUSE userspace client, afsd.fuse])],,
+    [enable_fuse_client="no"])
+
+if test "x$enable_fuse_client" = "xyes" ; then
+   PKG_PROG_PKG_CONFIG
+   PKG_CHECK_MODULES([FUSE], [fuse])
+   ENABLE_FUSE_CLIENT=afsd.fuse
+   CLIENT_UAFS_DEP=libuafs
+fi
+
+AC_SUBST(ENABLE_FUSE_CLIENT)
+AC_SUBST(CLIENT_UAFS_DEP)
+AC_SUBST(FUSE_CFLAGS)
+AC_SUBST(FUSE_LIBS)
+
+])dnl