/* kernel_interface.c: interface to fuse and coda kernel mocule. Copyright (C) 2006, 2007, 2008, 2009 Werner Baumann This file is part of davfs2. davfs2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. davfs2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with davfs2; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #ifdef HAVE_FCNTL_H #include #endif #ifdef HAVE_LIBINTL_H #include #endif #ifdef HAVE_STDDEF_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_SYSLOG_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_SYS_MOUNT_H #include #endif #include "defaults.h" #include "mount_davfs.h" #include "cache.h" //#include "coda.h" #include "kernel_interface.h" #ifdef ENABLE_NLS #define _(String) gettext(String) #else #define _(String) String #endif /* Private constants */ /*===================*/ /* Name, major number and minor number of the devices to communicate with the kernel file system. */ //#define CODA_DEV_NAME "cfs" //#define CODA_MAJOR 67 //#define MAX_CODADEVS 5 /* Coda minor number may be from 0 to 4. */ #define FUSE_DEV_NAME "fuse" #define FUSE_MAJOR 10 #define FUSE_MINOR 229 /* Minimum size of buffer for fuse. Must be big enough for any version.*/ #define FUSE_MIN_READ_BUFFER 16384 /* Private function prototypes */ /*=============================*/ /*static int init_coda(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata);*/ static int init_fuse(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata, size_t *buf_size, const char *url, const char *mpoint, unsigned long int mopts, uid_t owner, gid_t group, mode_t mode); /* Public functions */ /*==================*/ int dav_init_kernel_interface(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata, char **kernel_fs, size_t *buf_size, const char *url, const char *mpoint, const dav_args *args) { uid_t orig = geteuid(); seteuid(0); if (!*kernel_fs) *kernel_fs = strdup("fuse"); if (!*kernel_fs) abort(); int mounted = 0; /* if (strcmp(*kernel_fs, "coda") == 0) { if (init_coda(dev, msg_loop, mdata) != 0) { error(0, 0, _("trying fuse kernel file system")); if (init_fuse(dev, msg_loop, mdata, buf_size, url, mpoint, args->mopts, args->uid, args->gid, args->dir_mode) == 0) { free(*kernel_fs); *kernel_fs = strdup("fuse"); if (!*kernel_fs) abort(); mounted = 1; error(0, 0, _("fuse device opened successfully")); } else { exit(EXIT_FAILURE); } } } else */ if (strcmp(*kernel_fs, "fuse") == 0) { if (init_fuse(dev, msg_loop, mdata, buf_size, url, mpoint, args->mopts, args->uid, args->gid, args->dir_mode) == 0) { mounted = 1; } else { /*error(0, 0, _("trying coda kernel file system")); if (init_coda(dev, msg_loop, mdata) == 0) { free(*kernel_fs); *kernel_fs = strdup("coda"); if (*kernel_fs == NULL) abort(); error(0, 0, _("coda device opened successfully")); } else { exit(EXIT_FAILURE); }*/ exit(EXIT_FAILURE); } } else { error(EXIT_FAILURE, 0, _("unknown kernel file system %s"), *kernel_fs); } seteuid(orig); return mounted; } /* Private functions */ /*===================*/ /*static int init_coda(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata) { *dev = 0; int minor = 0; while (*dev <= 0 && minor < MAX_CODADEVS) { char *path; if (asprintf(&path, "%s/%s%i", DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0) abort(); *dev = open(path, O_RDWR | O_NONBLOCK); free(path); ++minor; } if (*dev <= 0) { system("/sbin/modprobe coda &>/dev/null"); minor = 0; while (*dev <= 0 && minor < MAX_CODADEVS) { char *path; if (asprintf(&path, "%s/%s%i", DAV_DEV_DIR, CODA_DEV_NAME, minor) < 0) abort(); *dev = open(path, O_RDWR | O_NONBLOCK); if (*dev <= 0) { if (mknod(path, S_IFCHR, makedev(CODA_MAJOR, minor)) == 0) { chown(path, 0, 0); chmod(path, S_IRUSR | S_IWUSR); *dev = open(path, O_RDWR | O_NONBLOCK); } } free(path); ++minor; } } if (*dev <= 0) { error(0, 0, _("no free coda device to mount")); return -1; } int version = 0; ioctl(*dev, CIOC_KERNEL_VERSION, &version); if (version == 2) { #if SIZEOF_VOID_P == 8 error(0, 0, _("CODA_KERNEL_VERSION %u can not be used on 64 bit systems"), version); close(*dev); return -1; #else *msg_loop = dav_coda2_loop; #endif } else if (version == 3) { *msg_loop = dav_coda3_loop; } else { error(0, 0, _("CODA_KERNEL_VERSION %u not supported"), version); close(*dev); return -1; } struct coda_mount_data *md = malloc(sizeof(struct coda_mount_data)); if (!md) abort(); md->version = CODA_MOUNT_VERSION; md->fd = *dev; *mdata = md; return 0; }*/ static int init_fuse(int *dev, dav_run_msgloop_fn *msg_loop, void **mdata, size_t *buf_size, const char *url, const char *mpoint, unsigned long int mopts, uid_t owner, gid_t group, mode_t mode) { char *path; if (asprintf(&path, "%s/%s", DAV_DEV_DIR, FUSE_DEV_NAME) < 0) abort(); *dev = open(path, O_RDWR | O_NONBLOCK); if (*dev <= 0) { system("/sbin/modprobe fuse &>/dev/null"); *dev = open(path, O_RDWR | O_NONBLOCK); } if (*dev <= 0) { if (mknod(path, S_IFCHR, makedev(FUSE_MAJOR, FUSE_MINOR)) == 0) { chown(path, 0, 0); chmod(path, S_IRUSR | S_IWUSR); *dev = open(path, O_RDWR | O_NONBLOCK); } } free(path); if (*dev <= 0) { error(0, 0, _("can't open fuse device")); return -1; } if (*buf_size < (FUSE_MIN_READ_BUFFER + 4096)) { *buf_size = FUSE_MIN_READ_BUFFER + 4096; } /* fuse kernel version 7 demands option group_id. */ #if SIZEOF_VOID_P == 8 if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,group_id=%i," "allow_other,max_read=%lu", *dev, mode, owner, group, *buf_size - 4096) < 0) abort(); #else if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,group_id=%i," "allow_other,max_read=%u", *dev, mode, owner, group, *buf_size - 4096) < 0) abort(); #endif if (mount(url, mpoint, "fuse", mopts, *mdata) == 0) { *msg_loop = dav_fuse7_loop; return 0; } /* fuse kernel version 5 does not allow option group_id. */ /* free(*mdata); #if SIZEOF_VOID_P == 8 if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,allow_other,max_read=%lu", *dev, mode, owner, *buf_size - 4096) < 0) abort(); #else if (asprintf((char **) mdata, "fd=%i,rootmode=%o,user_id=%i,allow_other,max_read=%u", *dev, mode, owner, *buf_size - 4096) < 0) abort(); #endif if (mount(url, mpoint, "fuse", mopts, *mdata) == 0) { *msg_loop = dav_fuse5_loop; return 0; } */ free(*mdata); close(*dev); error(0, 0, _("can't mount using fuse kernel file system")); return -1; }