From 38a80c33233852d47a124a26fe7428543df6a10f Mon Sep 17 00:00:00 2001 From: Andrew Deason Date: Thu, 8 Apr 2010 14:50:18 -0500 Subject: [PATCH] Add a FUSE implementation for afsd 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 Reviewed-by: Derrick Brashear Tested-by: Derrick Brashear --- Makefile.in | 2 +- acinclude.m4 | 1 + src/LICENSE | 47 ++-- src/afs/UKERNEL/afs_usrops.h | 1 + src/afsd/Makefile.in | 14 +- src/afsd/afsd_fuse.c | 563 +++++++++++++++++++++++++++++++++++++++++++ src/cf/fuse.m4 | 25 ++ 7 files changed, 626 insertions(+), 27 deletions(-) create mode 100644 src/afsd/afsd_fuse.c create mode 100644 src/cf/fuse.m4 diff --git a/Makefile.in b/Makefile.in index 798dc48..d0ef3be 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/acinclude.m4 b/acinclude.m4 index e2eb9c5..80cb33a 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1524,6 +1524,7 @@ AC_SUBST(XSLTPROC) OPENAFS_OSCONF OPENAFS_KRB5CONF +OPENAFS_FUSE TOP_SRCDIR="${srcdir}/src" dnl diff --git a/src/LICENSE b/src/LICENSE index 36a54eb..c71bb0a 100644 --- a/src/LICENSE +++ b/src/LICENSE @@ -232,39 +232,38 @@ 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: /* diff --git a/src/afs/UKERNEL/afs_usrops.h b/src/afs/UKERNEL/afs_usrops.h index c3c8c20..1ca506e 100644 --- a/src/afs/UKERNEL/afs_usrops.h +++ b/src/afs/UKERNEL/afs_usrops.h @@ -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__ */ diff --git a/src/afsd/Makefile.in b/src/afsd/Makefile.in index d1c2d71..7511cfa 100644 --- a/src/afsd/Makefile.in +++ b/src/afsd/Makefile.in @@ -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 index 0000000..4e6cc5c --- /dev/null +++ b/src/afsd/afsd_fuse.c @@ -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 +#include + +#include +#include +#include +#include +#include + +#include "afsd.h" + +#include +#include +#include + +#define FUSE_USE_VERSION 27 +#include + +/* 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 index 0000000..9b0ee6f --- /dev/null +++ b/src/cf/fuse.m4 @@ -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 -- 1.9.4