From 2df1c04f30802df9a23a19e22042884430c429d2 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Tue, 6 Nov 2001 15:07:17 +0000 Subject: [PATCH] cleanups --- .cvsignore | 2 +- Makefile | 20 +++-- fusepro.c => fusexmp.c | 180 +++++++++++++++++++++++++++++++---------- include/fuse.h | 92 ++++++++++++++++++++- include/linux/fuse.h | 3 +- kernel/fuse_i.h | 2 - kernel/inode.c | 13 +-- kernel/util.c | 4 +- lib/Makefile | 8 +- lib/fuse.c | 41 +++++++--- lib/fuse_i.h | 3 +- lib/mount.c | 22 ++--- usermux.c | 4 +- 13 files changed, 304 insertions(+), 90 deletions(-) rename fusepro.c => fusexmp.c (52%) diff --git a/.cvsignore b/.cvsignore index 5743e9b..d6dac71 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,2 +1,2 @@ -fusepro +fusexmp avfsd diff --git a/Makefile b/Makefile index 97d19d4..92d91ad 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,12 @@ CC = gcc CFLAGS = -Wall -g `glib-config --cflags` -LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/ +LDFLAGS = `glib-config --libs` -ldl -L ../avfs/libneon/ -L lib #LIBXML = -lxml LIBXML = -lxmltok -lxmlparse -LDLIBS = -lneon $(LIBXML) -lpthread +LDLIBS = -lneon $(LIBXML) -lfuse -lpthread CPPFLAGS = -Iinclude -I ../avfs/include - - -all: kernel/fuse.o fusepro avfsd +all: kernel/fuse.o fusexmp avfsd kernel/fuse.o: FORCE make -C kernel fuse.o @@ -16,15 +14,21 @@ kernel/fuse.o: FORCE lib/libfuse.a: FORCE make -C lib libfuse.a -fusepro: fusepro.o lib/libfuse.a +lib/libfuse.so: FORCE + make -C lib libfuse.so + +fusexmp: fusexmp.o lib/libfuse.so + gcc $(CFLAGS) $(LDFLAGS) -o fusexmp fusexmp.o $(LDLIBS) -avfsd: usermux.o avfsd.o ../avfs/lib/avfs.o lib/libfuse.a +avfsd_objs = usermux.o avfsd.o ../avfs/lib/avfs.o +avfsd: $(avfsd_objs) lib/libfuse.so + gcc $(CFLAGS) $(LDFLAGS) -o avfsd $(avfsd_objs) $(LDLIBS) clean: make -C kernel clean make -C lib clean rm -f *.o - rm -f fusepro avfsd + rm -f fusexmp avfsd rm -f *~ FORCE: diff --git a/fusepro.c b/fusexmp.c similarity index 52% rename from fusepro.c rename to fusexmp.c index ce32000..b00039d 100644 --- a/fusepro.c +++ b/fusexmp.c @@ -3,6 +3,9 @@ #define _XOPEN_SOURCE 500 #endif +/* For setgroups() */ +#define _BSD_SOURCE + #include #include #include @@ -12,27 +15,58 @@ #include #include #include +#include +#include -static struct fuse *pro_fuse; +static struct fuse *xmp_fuse; -static int pro_getattr(struct fuse_cred *cred, const char *path, +static int set_creds(struct fuse_cred *cred) +{ + int res; + + res = setfsuid(cred->uid); + if(res == -1) + return -errno; + + res = setfsgid(cred->gid); + if(res == -1) + return -errno; + + return 0; +} + +static void restore_creds() +{ + setfsuid(getuid()); + setfsgid(getgid()); +} + +static int xmp_getattr(struct fuse_cred *cred, const char *path, struct stat *stbuf) { int res; + res = set_creds(cred); + if(res) + return res; res = lstat(path, stbuf); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_readlink(struct fuse_cred *cred, const char *path, char *buf, +static int xmp_readlink(struct fuse_cred *cred, const char *path, char *buf, size_t size) { int res; + res = set_creds(cred); + if(res) + return res; res = readlink(path, buf, size - 1); + restore_creds(); if(res == -1) return -errno; @@ -41,14 +75,18 @@ static int pro_readlink(struct fuse_cred *cred, const char *path, char *buf, } -static int pro_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h, +static int xmp_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h, fuse_dirfil_t filler) { DIR *dp; struct dirent *de; int res; + res = set_creds(cred); + if(res) + return res; dp = opendir(path); + restore_creds(); if(dp == NULL) return -errno; @@ -62,125 +100,169 @@ static int pro_getdir(struct fuse_cred *cred, const char *path, fuse_dirh_t h, return res; } -static int pro_mknod(struct fuse_cred *cred, const char *path, mode_t mode, +static int xmp_mknod(struct fuse_cred *cred, const char *path, mode_t mode, dev_t rdev) { int res; + res = set_creds(cred); + if(res) + return res; res = mknod(path, mode, rdev); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_mkdir(struct fuse_cred *cred, const char *path, mode_t mode) +static int xmp_mkdir(struct fuse_cred *cred, const char *path, mode_t mode) { int res; + res = set_creds(cred); + if(res) + return res; res = mkdir(path, mode); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_unlink(struct fuse_cred *cred, const char *path) +static int xmp_unlink(struct fuse_cred *cred, const char *path) { int res; + res = set_creds(cred); + if(res) + return res; res = unlink(path); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_rmdir(struct fuse_cred *cred, const char *path) +static int xmp_rmdir(struct fuse_cred *cred, const char *path) { int res; + res = set_creds(cred); + if(res) + return res; res = rmdir(path); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_symlink(struct fuse_cred *cred, const char *from, +static int xmp_symlink(struct fuse_cred *cred, const char *from, const char *to) { int res; + res = set_creds(cred); + if(res) + return res; res = symlink(from, to); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_rename(struct fuse_cred *cred, const char *from, const char *to) +static int xmp_rename(struct fuse_cred *cred, const char *from, const char *to) { int res; + res = set_creds(cred); + if(res) + return res; res = rename(from, to); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_link(struct fuse_cred *cred, const char *from, const char *to) +static int xmp_link(struct fuse_cred *cred, const char *from, const char *to) { int res; + res = set_creds(cred); + if(res) + return res; res = link(from, to); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_chmod(struct fuse_cred *cred, const char *path, mode_t mode) +static int xmp_chmod(struct fuse_cred *cred, const char *path, mode_t mode) { int res; + res = set_creds(cred); + if(res) + return res; res = chmod(path, mode); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_chown(struct fuse_cred *cred, const char *path, uid_t uid, +static int xmp_chown(struct fuse_cred *cred, const char *path, uid_t uid, gid_t gid) { int res; + res = set_creds(cred); + if(res) + return res; res = lchown(path, uid, gid); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_truncate(struct fuse_cred *cred, const char *path, off_t size) +static int xmp_truncate(struct fuse_cred *cred, const char *path, off_t size) { int res; + res = set_creds(cred); + if(res) + return res; res = truncate(path, size); + restore_creds(); if(res == -1) return -errno; return 0; } -static int pro_utime(struct fuse_cred *cred, const char *path, +static int xmp_utime(struct fuse_cred *cred, const char *path, struct utimbuf *buf) { int res; + res = set_creds(cred); + if(res) + return res; res = utime(path, buf); + restore_creds(); if(res == -1) return -errno; @@ -188,11 +270,15 @@ static int pro_utime(struct fuse_cred *cred, const char *path, } -static int pro_open(struct fuse_cred *cred, const char *path, int flags) +static int xmp_open(struct fuse_cred *cred, const char *path, int flags) { int res; + res = set_creds(cred); + if(res) + return res; res = open(path, flags); + restore_creds(); if(res == -1) return -errno; @@ -200,13 +286,17 @@ static int pro_open(struct fuse_cred *cred, const char *path, int flags) return 0; } -static int pro_read(struct fuse_cred *cred, const char *path, char *buf, +static int xmp_read(struct fuse_cred *cred, const char *path, char *buf, size_t size, off_t offset) { int fd; int res; + res = set_creds(cred); + if(res) + return res; fd = open(path, O_RDONLY); + restore_creds(); if(fd == -1) return -errno; @@ -218,13 +308,17 @@ static int pro_read(struct fuse_cred *cred, const char *path, char *buf, return res; } -static int pro_write(struct fuse_cred *cred, const char *path, const char *buf, +static int xmp_write(struct fuse_cred *cred, const char *path, const char *buf, size_t size, off_t offset) { int fd; int res; + res = set_creds(cred); + if(res) + return res; fd = open(path, O_WRONLY); + restore_creds(); if(fd == -1) return -errno; @@ -267,28 +361,28 @@ static void set_signal_handlers() static void cleanup() { - fuse_unmount(pro_fuse); - fuse_destroy(pro_fuse); + fuse_unmount(xmp_fuse); + fuse_destroy(xmp_fuse); } -static struct fuse_operations pro_oper = { - getattr: pro_getattr, - readlink: pro_readlink, - getdir: pro_getdir, - mknod: pro_mknod, - mkdir: pro_mkdir, - symlink: pro_symlink, - unlink: pro_unlink, - rmdir: pro_rmdir, - rename: pro_rename, - link: pro_link, - chmod: pro_chmod, - chown: pro_chown, - truncate: pro_truncate, - utime: pro_utime, - open: pro_open, - read: pro_read, - write: pro_write, +static struct fuse_operations xmp_oper = { + getattr: xmp_getattr, + readlink: xmp_readlink, + getdir: xmp_getdir, + mknod: xmp_mknod, + mkdir: xmp_mkdir, + symlink: xmp_symlink, + unlink: xmp_unlink, + rmdir: xmp_rmdir, + rename: xmp_rename, + link: xmp_link, + chmod: xmp_chmod, + chown: xmp_chown, + truncate: xmp_truncate, + utime: xmp_utime, + open: xmp_open, + read: xmp_read, + write: xmp_write, }; int main(int argc, char *argv[]) @@ -301,14 +395,16 @@ int main(int argc, char *argv[]) set_signal_handlers(); atexit(cleanup); + setgroups(0, NULL); - pro_fuse = fuse_new(0); - res = fuse_mount(pro_fuse, argv[1]); + xmp_fuse = fuse_new(0,0); + res = fuse_mount(xmp_fuse, argv[1]); if(res == -1) exit(1); - fuse_set_operations(pro_fuse, &pro_oper); - fuse_loop(pro_fuse); + fuse_set_operations(xmp_fuse, &xmp_oper); + + fuse_loop(xmp_fuse); return 0; } diff --git a/include/fuse.h b/include/fuse.h index 4edb0c7..4cddaaf 100644 --- a/include/fuse.h +++ b/include/fuse.h @@ -12,16 +12,56 @@ #include #include +/** Handle for a FUSE filesystem */ struct fuse; + +/** Handle for a getdir() operation */ typedef struct fuse_dirhandle *fuse_dirh_t; +/** Function to add an entry in a getdir() operation */ typedef int (*fuse_dirfil_t) (fuse_dirh_t, const char *, int type); +/** Credentials for an operation, these are determined by the fsuid + and fsgid of the calling process */ struct fuse_cred { uid_t uid; gid_t gid; + /* FIXME: supplementary groups should also be included */ }; +/** + * The file system operations: + * + * Most of these should work very similarly to the well known UNIX + * file system operations. Exceptions are: + * + * - All operations get a fuse_cred structure by which the filesystem + * implementation can check, whether the operation is permitted or + * not. + * + * - All operations should return the negated error value (-errno) on + * error. + * + * - readlink() should fill the buffer with a null terminated string. + * The buffer size argument includes the space for the terminating + * null character. If the linkname is too long to fit in the buffer, + * it should be truncated. The return value should be 0 for success. + * + * - getdir() is the opendir(), readdir(), ..., closedir() sequence + * in one call. For each directory entry the filldir parameter should + * be called. + * + * - There is no create() operation, mknod() will be called for + * creation of all non directory, non symlink nodes. + * + * - open() should not return a filehandle, but 0 on success. No + * creation, or trunctation flags (O_CREAT, O_EXCL, O_TRUNC) will be + * passed to open(). Open should only check if the operation is + * permitted for the given flags. + * + * - read(), write() are not passed a filehandle, but rather a + * pathname. The offset of the read and write is passed as the last + * argument, like the pread() and pwrite() system calls. */ struct fuse_operations { int (*getattr) (struct fuse_cred *, const char *, struct stat *); int (*readlink) (struct fuse_cred *, const char *, char *, size_t); @@ -42,16 +82,64 @@ struct fuse_operations { int (*write) (struct fuse_cred *, const char *, const char *, size_t, off_t); }; +/* FUSE flags: */ #define FUSE_MULTITHREAD (1 << 0) -struct fuse *fuse_new(int flags); +/** + * Create a new FUSE filesystem. The filesystem is not yet mounted + * + * @param flags any combination of the FUSE flags defined above, or 0 + * @param root the file type of the root node. 0 is the default (directory). + * @return the created FUSE handle + */ +struct fuse *fuse_new(int flags, mode_t root); -int fuse_mount(struct fuse *f, const char *dir); +/** + * Connect to the kernel and mount the filesystem. + * + * @param f the FUSE handle + * @param mnt the mount point + * @return 0 on success -1 on failure + */ +int fuse_mount(struct fuse *f, const char *mnt); +/** + * Set the filesystem operations. + * + * Operations which are initialised to NULL will return ENOSYS to the + * calling process. This function can be called anytime after + * fuse_new() and before fuse_loop(). + * + * @param f the FUSE handle + * @param op the operations + */ void fuse_set_operations(struct fuse *f, const struct fuse_operations *op); +/** + * FUSE event loop. + * + * Requests from the kernel are processed, and the apropriate + * operations are called. + * + * @param f the FUSE handle + */ void fuse_loop(struct fuse *f); +/** + * Disconnect from the kernel and unmount the filesystem + * + * @param f the FUSE handle + */ int fuse_unmount(struct fuse *f); +/** + * Destroy the filesystem. + * + * The filesystem is not unmounted (call fuse_unmount() for that). + * After a fork() system call it is possible to call fuse_destroy() in + * one process, and leave the other process to service the filesystem + * requests. + * + * @param f the FUSE handle + */ void fuse_destroy(struct fuse *f); diff --git a/include/linux/fuse.h b/include/linux/fuse.h index a6e74df..22897d4 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h @@ -9,11 +9,12 @@ /* This file defines the kernel interface of FUSE */ -#define FUSE_MOUNT_VERSION 1 +#define FUSE_KERNEL_VERSION 1 struct fuse_mount_data { int version; int fd; + unsigned int rootmode; }; #define FUSE_ROOT_INO 1 diff --git a/kernel/fuse_i.h b/kernel/fuse_i.h index b738bed..b3f3a9c 100644 --- a/kernel/fuse_i.h +++ b/kernel/fuse_i.h @@ -12,8 +12,6 @@ #include #include -#define FUSE_VERSION "0.1" - #define MAX_CLEARED 256 /** diff --git a/kernel/inode.c b/kernel/inode.c index 77e8469..5fb4a66 100644 --- a/kernel/inode.c +++ b/kernel/inode.c @@ -66,8 +66,8 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) return NULL; } - if(d->version != FUSE_MOUNT_VERSION) { - printk("fuse_read_super: Bad mount version: %i\n", d->version); + if(d->version != FUSE_KERNEL_VERSION) { + printk("fuse_read_super: Bad version: %i\n", d->version); return NULL; } @@ -89,12 +89,12 @@ static struct fuse_conn *get_conn(struct fuse_mount_data *d) } -static struct inode *get_root_inode(struct super_block *sb) +static struct inode *get_root_inode(struct super_block *sb, unsigned int mode) { struct fuse_attr attr; memset(&attr, 0, sizeof(attr)); - attr.mode = S_IFDIR; + attr.mode = mode; return fuse_iget(sb, 1, &attr, 0); } @@ -103,20 +103,21 @@ static struct super_block *fuse_read_super(struct super_block *sb, { struct fuse_conn *fc; struct inode *root; + struct fuse_mount_data *d = data; sb->s_blocksize = 1024; sb->s_blocksize_bits = 10; sb->s_magic = FUSE_SUPER_MAGIC; sb->s_op = &fuse_super_operations; - root = get_root_inode(sb); + root = get_root_inode(sb, d->rootmode); if(root == NULL) { printk("fuse_read_super: failed to get root inode\n"); return NULL; } spin_lock(&fuse_lock); - fc = get_conn(data); + fc = get_conn(d); if(fc == NULL) goto err; diff --git a/kernel/util.c b/kernel/util.c index 57b1a90..9b7bec1 100644 --- a/kernel/util.c +++ b/kernel/util.c @@ -12,8 +12,6 @@ #include #include -#define FUSE_VERSION "0.1" - spinlock_t fuse_lock = SPIN_LOCK_UNLOCKED; /* Must be called with the fuse lock held */ @@ -28,7 +26,7 @@ int init_module(void) { int res; - printk(KERN_DEBUG "fuse init (version %s)\n", FUSE_VERSION); + printk(KERN_DEBUG "fuse init (version %i)\n", FUSE_KERNEL_VERSION); res = fuse_fs_init(); if(res) diff --git a/lib/Makefile b/lib/Makefile index e72a39d..88b087a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,16 +1,18 @@ CC = gcc -CFLAGS = -Wall -W -g `glib-config --cflags` +CFLAGS = -Wall -W -g `glib-config --cflags` -fPIC LDFLAGS = `glib-config --libs` CPPFLAGS = -I../include - -all: libfuse.a +all: libfuse.a libfuse.so libfuse_objs = mount.o fuse.o libfuse.a: $(libfuse_objs) ar cr libfuse.a $(libfuse_objs) +libfuse.so: $(libfuse_objs) + gcc -shared -o libfuse.so $(libfuse_objs) + clean: rm -f *.o *.a rm -f *~ diff --git a/lib/fuse.c b/lib/fuse.c index 137b5ef..b12c58d 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -407,6 +407,7 @@ static void do_readlink(struct fuse *f, struct fuse_in_header *in) res = f->op.readlink(&cred, path, link, sizeof(link)); g_free(path); } + link[PATH_MAX] = '\0'; send_reply(f, in, res, link, !res ? strlen(link) : 0); } @@ -756,6 +757,17 @@ static void *do_command(void *data) return NULL; } +/* This hack makes it possible to link FUSE with or without the + pthread library */ +__attribute__((weak)) +int pthread_create(pthread_t *thrid __attribute__((unused)), + const pthread_attr_t *attr __attribute__((unused)), + void *(*func)(void *) __attribute__((unused)), + void *arg __attribute__((unused))) +{ + return ENOSYS; +} + void fuse_loop(struct fuse *f) { int res; @@ -787,24 +799,35 @@ void fuse_loop(struct fuse *f) if(f->flags & FUSE_MULTITHREAD) { res = pthread_create(&thrid, &attr, do_command, cmd); - if(res != 0) { - fprintf(stderr, "Error creating thread: %s\n", - strerror(errno)); - exit(1); - } + if(res == 0) + continue; + + fprintf(stderr, "Error creating thread: %s\n", strerror(res)); + fprintf(stderr, "Will run in single thread mode\n"); + f->flags &= ~FUSE_MULTITHREAD; } - else - do_command(cmd); + + do_command(cmd); } } -struct fuse *fuse_new(int flags) +struct fuse *fuse_new(int flags, mode_t root) { struct fuse *f = g_new0(struct fuse, 1); + if(!root) + root = S_IFDIR; + + if(!S_ISDIR(root) && !S_ISREG(root)) { + fprintf(stderr, "Invalid mode for root: 0%o\n", root); + root = S_IFDIR; + } + root &= S_IFMT; + f->flags = flags; + f->rootmode = root; f->fd = -1; - f->dir = NULL; + f->mnt = NULL; f->nametab = g_hash_table_new((GHashFunc) name_hash, (GCompareFunc) name_compare); pthread_mutex_init(&f->lock, NULL); diff --git a/lib/fuse_i.h b/lib/fuse_i.h index c28e2e8..6f363d8 100644 --- a/lib/fuse_i.h +++ b/lib/fuse_i.h @@ -25,7 +25,8 @@ struct node { struct fuse { int flags; - char *dir; + char *mnt; + mode_t rootmode; int fd; struct fuse_operations op; GHashTable *nametab; diff --git a/lib/mount.c b/lib/mount.c index 48d9d45..98d9e59 100644 --- a/lib/mount.c +++ b/lib/mount.c @@ -16,13 +16,15 @@ #include #include -static int do_mount(const char *dev, const char *dir, const char *type, int fd) +static int do_mount(const char *dev, const char *dir, const char *type, + mode_t rootmode, int fd) { int res; struct fuse_mount_data data; - data.version = FUSE_MOUNT_VERSION; + data.version = FUSE_KERNEL_VERSION; data.fd = fd; + data.rootmode = rootmode; res = mount(dev, dir, type, MS_MGC_VAL | MS_NOSUID | MS_NODEV, &data); if(res == -1) { @@ -100,7 +102,7 @@ int fuse_mount(struct fuse *f, const char *dir) const char *dev = FUSE_DEV; const char *type = "fuse"; - if(f->dir != NULL) + if(f->mnt != NULL) return 0; f->fd = open(dev, O_RDWR); @@ -109,12 +111,12 @@ int fuse_mount(struct fuse *f, const char *dir) return -1; } - res = do_mount(dev, dir, type, f->fd); + res = do_mount(dev, dir, type, f->rootmode, f->fd); if(res == -1) return -1; add_mntent(dev, dir, type); - f->dir = g_strdup(dir); + f->mnt = g_strdup(dir); return 0; } @@ -123,20 +125,20 @@ int fuse_unmount(struct fuse *f) { int res; - if(f->dir == NULL) + if(f->mnt == NULL) return 0; close(f->fd); f->fd = -1; - res = umount(f->dir); + res = umount(f->mnt); if(res == -1) perror("umount failed"); else - remove_mntent(f->dir); + remove_mntent(f->mnt); - g_free(f->dir); - f->dir = NULL; + g_free(f->mnt); + f->mnt = NULL; return res; } diff --git a/usermux.c b/usermux.c index 4caacb9..f2f11f3 100644 --- a/usermux.c +++ b/usermux.c @@ -50,7 +50,7 @@ static void start_avfs(uid_t uid) if(pw == NULL) return; - user_fuse = fuse_new(0); + user_fuse = fuse_new(FUSE_MULTITHREAD, 0); userdir = g_strdup_printf("%s/%010u", MOUNTDIR, uid); mkdir(userdir, 0755); @@ -240,7 +240,7 @@ int main(int argc, char *argv[]) set_signal_handlers(); atexit(cleanup); - um_fuse = fuse_new(0); + um_fuse = fuse_new(FUSE_MULTITHREAD, 0); res = fuse_mount(um_fuse, um_dir); if(res == -1) exit(1); -- 2.30.2