From: Miklos Szeredi Date: Wed, 21 Nov 2001 10:03:39 +0000 (+0000) Subject: writing modules made more easy X-Git-Tag: fuse_0_95~16 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=cc8c975f7757ce89d15aad31df6c8b7086169653;p=qemu-gpiodev%2Flibfuse.git 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 @@ Makefile .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 #include -#include #include +#include #include #include -#include -#include -#include static int xmp_getattr(const char *path, struct stat *stbuf) { @@ -237,7 +231,6 @@ static int xmp_write(const char *path, const char *buf, size_t size, return res; } - static struct fuse_operations xmp_oper = { getattr: xmp_getattr, readlink: xmp_readlink, @@ -258,93 +251,8 @@ static struct fuse_operations xmp_oper = { 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 +#include +#include +#include + +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 -#include -#include -#include -#include + #include -#include #include +#include #define UNUSED __attribute__((unused)) @@ -88,93 +85,8 @@ static struct fuse_operations null_oper = { 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 #include +/* ----------------------------------------------------------- * + * Basic FUSE API * + * ----------------------------------------------------------- */ + /** Handle for a FUSE filesystem */ struct fuse; @@ -81,6 +85,7 @@ struct fuse_operations { /** Enable debuging output */ #define FUSE_DEBUG (1 << 1) + /** * Create a new FUSE filesystem. * @@ -108,6 +113,7 @@ void fuse_set_operations(struct fuse *f, const struct fuse_operations *op); * 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_loop_mt(struct fuse *f); */ 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 @@ lib_LIBRARIES = libfuse.a 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 *fuse_new(int fd, int flags) 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 +#include +#include +#include +#include +#include +#include + +#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 @@ int main(int argc, char *argv[]) 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],