new 'simple' module, plus hello_simple
authorTero Marttila <terom@fixme.fi>
Fri, 26 Sep 2008 20:11:22 +0300
changeset 6 d2036d7799fd
parent 5 dc86636257c2
child 7 3a603d755bcb
new 'simple' module, plus hello_simple
Makefile
src/evfuse.c
src/hello.c
src/lib/common.c
src/lib/common.h
src/lib/log.c
src/lib/log.h
src/lib/misc.h
src/simple.c
src/simple.h
src/simple_hello.c
--- a/Makefile	Fri Sep 26 15:35:58 2008 +0300
+++ b/Makefile	Fri Sep 26 20:11:22 2008 +0300
@@ -12,7 +12,8 @@
 BIN_NAMES = hello helloworld
 
 bin/helloworld: 
-bin/hello: obj/evfuse.o obj/lib/common.o obj/lib/signals.o
+bin/hello: obj/evfuse.o obj/lib/log.o obj/lib/signals.o
+bin/simple_hello: obj/evfuse.o obj/lib/log.o obj/lib/signals.o obj/simple.o
 
 # computed
 LDFLAGS = ${LIBRARY_PATHS} ${LIBRARY_LIST}
--- a/src/evfuse.c	Fri Sep 26 15:35:58 2008 +0300
+++ b/src/evfuse.c	Fri Sep 26 20:11:22 2008 +0300
@@ -4,7 +4,7 @@
 #include <stdlib.h>
 
 #include "evfuse.h"
-#include "lib/common.h"
+#include "lib/log.h"
 
 struct evfuse {
     // our mountpoint
@@ -58,8 +58,8 @@
     return;
 
 error:
-    // XXX: fail
-    FATAL("no error handling yet...");
+    // fail
+    evfuse_close(ctx);
 }
 
 struct evfuse *evfuse_new (struct event_base *evbase, struct fuse_args *args, struct fuse_lowlevel_ops *llops, void *cb_data) {
--- a/src/hello.c	Fri Sep 26 15:35:58 2008 +0300
+++ b/src/hello.c	Fri Sep 26 20:11:22 2008 +0300
@@ -5,7 +5,7 @@
 #include <event2/event.h>
 #include <fuse/fuse_opt.h>
 
-#include "lib/common.h"
+#include "lib/log.h"
 #include "lib/math.h"
 #include "lib/signals.h"
 #include "evfuse.h"
@@ -87,8 +87,6 @@
     size_t off;
 };
 
-#define DIRBUF_INITIAL_SIZE 1024
-
 static int dirbuf_init (struct dirbuf *buf, size_t req_size) {
     buf->len = req_size;
     buf->off = 0;
@@ -250,6 +248,12 @@
         EWARNING(err, "failed to send error reply");
 }
 
+void hello_getxattr (fuse_req_t req, fuse_ino_t ino, const char *name, size_t size) {
+    INFO("[hello.getxattr] ino=%lu, name=`%s', size=%zu", ino, name, size);
+
+    fuse_reply_err(req, ENOSYS);
+}
+
 struct fuse_lowlevel_ops hello_llops = {
     .init = &hello_init,
     .destroy = &hello_destroy,
@@ -262,6 +266,8 @@
     .read = &hello_read,
 
     .readdir = &hello_readdir,
+
+    .getxattr = hello_getxattr,
 };
 
 
--- a/src/lib/common.c	Fri Sep 26 15:35:58 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-
-#include "common.h"
-
-static void _generic_err_vargs (int use_stderr, const char *func, int perr, const char *fmt, va_list va) {
-    FILE *stream = use_stderr ? stderr : stdout;
-
-    if (func)
-        fprintf(stream, "%s: ", func);
-    
-    vfprintf(stream, fmt, va);
-    
-    if (perr)
-        fprintf(stream, ": %s\n", strerror(perr > 0 ? errno : -perr));
-
-    fprintf(stream, "\n");
-}
-
-void _generic_err (int use_stderr, const char *func, int perr, const char *fmt, ...) {
-    va_list va;
-
-    va_start(va, fmt);
-    _generic_err_vargs(use_stderr, func, perr, fmt, va);
-    va_end(va);
-}
-
-void _generic_err_exit (int use_stderr, const char *func, int perr, const char *fmt, ...) {
-    va_list va;
-
-    va_start(va, fmt);
-    _generic_err_vargs(use_stderr, func, perr, fmt, va);
-    va_end(va);
-      
-    exit(EXIT_FAILURE);
-}
-
--- a/src/lib/common.h	Fri Sep 26 15:35:58 2008 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-
-/*
- * error handling
- */
-
-void _generic_err ( /*int level, */ int use_stderr, const char *func, int perr, const char *fmt, ...)
-        __attribute__ ((format (printf, 4, 5)));
-
-// needs to be defined as its own function for the noreturn attribute
-void _generic_err_exit ( /* int level, */ int used_stderr, const char *func, int perr, const char *fmt, ...)
-        __attribute__ ((format (printf, 4, 5)))
-        __attribute__ ((noreturn));
-
-enum _debug_level {
-    DEBUG_FATAL,
-    DEBUG_ERROR,
-    DEBUG_WARNING,
-    DEBUG_INFO,
-    DEBUG_DEBUG,
-};
-
-// not currently used
-extern enum _debug_level _cur_debug_level;
-
-// various kinds of ways to handle an error, 2**3 of them, *g*
-#define info(...)                   _generic_err(       0,  NULL,   0,  __VA_ARGS__ )
-#define error(...)                  _generic_err(       1,  NULL,   0,  __VA_ARGS__ )
-#define err_exit(...)               _generic_err_exit(  1,  NULL,   0,  __VA_ARGS__ )
-#define perr(...)                   _generic_err(       1,  NULL,   1,  __VA_ARGS__ )
-#define perr_exit(...)              _generic_err_exit(  1,  NULL,   1,  __VA_ARGS__ )
-#define err_func(func, ...)         _generic_err(       1,  func,   0,  __VA_ARGS__ )
-#define err_func_exit(func, ...)    _generic_err_exit(  1,  func,   0,  __VA_ARGS__ )
-#define perr_func(func, ...)        _generic_err(       1,  func,   1,  __VA_ARGS__ )
-#define perr_func_exit(func, ...)   _generic_err_exit(  1,  func,   1,  __VA_ARGS__ )
-#define eerr_func(func, err, ...)   _generic_err(       1,  func,   err,__VA_ARGS__ )
-
-/*
- * error(func + colon + msg, ...) + goto error
- * err = negative error code
- */
-#define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0)
-#define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0)
-#define EERROR(err, ...) do { eerr_func(__func__, (err), __VA_ARGS__); goto error; } while (0)
-#define FATAL(...) err_func_exit(__func__, __VA_ARGS__)
-#define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__)
-#define WARNING(...) err_func(__func__, __VA_ARGS__)
-#define PWARNING(...) perr_func(__func__, __VA_ARGS__)
-#define EWARNING(err, ...) eerr_func(__func__, (err), __VA_ARGS__)
-
-#ifdef DEBUG_ENABLED
-#define DEBUG(...) err_func(__func__, __VA_ARGS__)
-#else
-#define DEBUG(...) (void) (0)
-#endif
-
-// default is to enable INFO
-#ifdef INFO_DISABLED
-    #define INFO_ENABLED 0
-#else
-    #ifndef INFO_ENABLED
-        #define INFO_ENABLED 1
-    #endif
-#endif
-
-#if INFO_ENABLED
-#define INFO(...) info(__VA_ARGS__)
-#else
-#define INFO(...) (void) (0)
-#endif
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/log.c	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,40 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+
+#include "log.h"
+
+static void _generic_err_vargs (int use_stderr, const char *func, int perr, const char *fmt, va_list va) {
+    FILE *stream = use_stderr ? stderr : stdout;
+
+    if (func)
+        fprintf(stream, "%s: ", func);
+    
+    vfprintf(stream, fmt, va);
+    
+    if (perr)
+        fprintf(stream, ": %s\n", strerror(perr > 0 ? errno : -perr));
+
+    fprintf(stream, "\n");
+}
+
+void _generic_err (int use_stderr, const char *func, int perr, const char *fmt, ...) {
+    va_list va;
+
+    va_start(va, fmt);
+    _generic_err_vargs(use_stderr, func, perr, fmt, va);
+    va_end(va);
+}
+
+void _generic_err_exit (int use_stderr, const char *func, int perr, const char *fmt, ...) {
+    va_list va;
+
+    va_start(va, fmt);
+    _generic_err_vargs(use_stderr, func, perr, fmt, va);
+    va_end(va);
+      
+    exit(EXIT_FAILURE);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/log.h	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,70 @@
+
+/*
+ * error handling
+ */
+
+void _generic_err ( /*int level, */ int use_stderr, const char *func, int perr, const char *fmt, ...)
+        __attribute__ ((format (printf, 4, 5)));
+
+// needs to be defined as its own function for the noreturn attribute
+void _generic_err_exit ( /* int level, */ int used_stderr, const char *func, int perr, const char *fmt, ...)
+        __attribute__ ((format (printf, 4, 5)))
+        __attribute__ ((noreturn));
+
+enum _debug_level {
+    DEBUG_FATAL,
+    DEBUG_ERROR,
+    DEBUG_WARNING,
+    DEBUG_INFO,
+    DEBUG_DEBUG,
+};
+
+// not currently used
+extern enum _debug_level _cur_debug_level;
+
+// various kinds of ways to handle an error, 2**3 of them, *g*
+#define info(...)                   _generic_err(       0,  NULL,   0,  __VA_ARGS__ )
+#define error(...)                  _generic_err(       1,  NULL,   0,  __VA_ARGS__ )
+#define err_exit(...)               _generic_err_exit(  1,  NULL,   0,  __VA_ARGS__ )
+#define perr(...)                   _generic_err(       1,  NULL,   1,  __VA_ARGS__ )
+#define perr_exit(...)              _generic_err_exit(  1,  NULL,   1,  __VA_ARGS__ )
+#define err_func(func, ...)         _generic_err(       1,  func,   0,  __VA_ARGS__ )
+#define err_func_exit(func, ...)    _generic_err_exit(  1,  func,   0,  __VA_ARGS__ )
+#define perr_func(func, ...)        _generic_err(       1,  func,   1,  __VA_ARGS__ )
+#define perr_func_exit(func, ...)   _generic_err_exit(  1,  func,   1,  __VA_ARGS__ )
+#define eerr_func(func, err, ...)   _generic_err(       1,  func,   err,__VA_ARGS__ )
+
+/*
+ * error(func + colon + msg, ...) + goto error
+ * err = negative error code
+ */
+#define ERROR(...) do { err_func(__func__, __VA_ARGS__); goto error; } while (0)
+#define PERROR(...) do { perr_func(__func__, __VA_ARGS__); goto error; } while (0)
+#define EERROR(err, ...) do { eerr_func(__func__, (err), __VA_ARGS__); goto error; } while (0)
+#define FATAL(...) err_func_exit(__func__, __VA_ARGS__)
+#define PFATAL(...) perr_func_exit(__func__, __VA_ARGS__)
+#define WARNING(...) err_func(__func__, __VA_ARGS__)
+#define PWARNING(...) perr_func(__func__, __VA_ARGS__)
+#define EWARNING(err, ...) eerr_func(__func__, (err), __VA_ARGS__)
+
+#ifdef DEBUG_ENABLED
+#define DEBUG(...) err_func(__func__, __VA_ARGS__)
+#else
+#define DEBUG(...) (void) (0)
+#endif
+
+// default is to enable INFO
+#ifdef INFO_DISABLED
+    #define INFO_ENABLED 0
+#else
+    #ifndef INFO_ENABLED
+        #define INFO_ENABLED 1
+    #endif
+#endif
+
+#if INFO_ENABLED
+#define INFO(...) info(__VA_ARGS__)
+#else
+#define INFO(...) (void) (0)
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/misc.h	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,10 @@
+#ifndef LIB_UTIL_H
+#define LIB_UTIL_H
+
+/*
+ * Initialize the given *value* with zeros
+ */
+#define ZINIT(obj) memset(&(obj), 0, sizeof((obj)))
+
+#endif /* LIB_UTIL_H */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simple.c	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,145 @@
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "simple.h"
+#include "lib/log.h"
+#include "lib/misc.h"
+
+struct simple_fs {
+    const struct simple_node *inode_table;
+
+    size_t inode_count;
+};
+
+/*
+ * Used for stat/entry timeouts... not sure how this should really be set.
+ */
+#define CACHE_TIMEOUT 1.0
+
+static void _simple_stat (struct stat *stat, const struct simple_node *node) {
+    stat->st_ino = node->inode;
+    stat->st_mode = node->mode_type | node->mode_perm;
+    stat->st_nlink = 1;
+    stat->st_size = node->data ? strlen(node->data) : 0;
+}
+
+static int _simple_check_ino (struct simple_fs *fs, fuse_ino_t ino) {
+    return (ino < 1 || ino > fs->inode_count) ? EIO : 0;
+}
+
+static void simple_lookup (fuse_req_t req, fuse_ino_t parent, const char *name) {
+    struct simple_fs *fs = fuse_req_userdata(req);
+    const struct simple_node *node;
+    struct fuse_entry_param e; ZINIT(e);
+    int err;
+    
+    INFO("[simple.lookup %p] parent=%lu, name=`%s'", fs, parent, name);
+
+    // find the matching node
+    for (node = fs->inode_table; node->inode > 0; node++) {
+        if (node->parent == parent && strcmp(node->name, name) == 0)
+            break;
+
+    }
+
+    // did we find it?
+    if (node->inode) {
+        // set up the entry
+        e.ino = node->inode;
+        e.generation = 0x01;
+        _simple_stat(&e.attr, node);
+        e.attr_timeout = CACHE_TIMEOUT;
+        e.entry_timeout = CACHE_TIMEOUT;
+
+        // reply
+        if ((err = fuse_reply_entry(req, &e)))
+            EERROR(err, "fuse_reply_entry");
+
+    } else {
+        // not found
+        err = ENOENT;
+        goto error;
+    }
+
+    // success
+    return;
+
+error:
+    if ((err = fuse_reply_err(req, err)))
+        EWARNING(err, "fuse_reply_err");
+}
+
+static void simple_getattr (fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi) {
+    struct simple_fs *fs = fuse_req_userdata(req);
+    const struct simple_node *node;
+    struct stat stbuf; ZINIT(stbuf);
+    int err;
+
+    INFO("[simple.getattr %p] ino=%lu", fs, ino);
+    
+    // make sure ino is valid
+    if ((err = _simple_check_ino(fs, ino)))
+        ERROR("invalid inode");
+
+    // look up the node
+    node = fs->inode_table + (ino - 1);
+
+    // set up the stbuf
+    _simple_stat(&stbuf, node);
+    
+    // reply
+    if ((err = fuse_reply_attr(req, &stbuf, CACHE_TIMEOUT)))
+        EERROR(err, "fuse_reply_attr");
+    
+    // suceccss
+    return;
+
+error:
+    if ((err = fuse_reply_err(req, err)))
+        EWARNING(err, "fuse_reply_err");
+}
+
+
+/*
+ * Define our fuse_lowlevel_ops struct.
+ */
+static struct fuse_lowlevel_ops simple_ops = {
+    .lookup = simple_lookup,
+
+    .getattr = simple_getattr,
+};
+
+struct fuse_lowlevel_ops *simple_init () {
+    return &simple_ops;
+}
+
+struct simple_fs *simple_new (const struct simple_node *node_list) {
+    struct simple_fs *fs = NULL;
+    const struct simple_node *node;
+    
+    // generate
+    if ((fs = calloc(1, sizeof(*fs))) == NULL)
+        ERROR("calloc");
+
+    // remember node_list
+    fs->inode_count = 0;
+    fs->inode_table = node_list;
+    
+    // validate it
+    for (node = fs->inode_table; node->inode; node++) {
+        // update inode_count
+        fs->inode_count++;
+
+        // check that parent is valid
+        assert(node->inode == fs->inode_count);
+        assert(node->parent < node->inode);
+    }
+    
+    // success
+    return fs;
+
+error:
+    return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simple.h	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,46 @@
+#ifndef SIMPLE_H
+#define SIMPLE_H
+
+/*
+ * A simple static in-memory filesystem structure.
+ */
+
+#include <fuse/fuse_lowlevel.h>
+
+/*
+ * A simple file/dir.
+ */
+struct simple_node {
+    // inode number
+    fuse_ino_t inode;
+
+    // mode
+    mode_t mode_type;
+    mode_t mode_perm;
+
+    // parent node
+    fuse_ino_t parent;
+
+    // name
+    const char *name;
+    
+    // data
+    const char *data;
+};
+
+/*
+ * General information.
+ */
+struct simple_fs;
+
+/*
+ * Initialize simple, and get the fuse_lowlevel_ops.
+ */
+struct fuse_lowlevel_ops *simple_init ();
+
+/*
+ * Create a new simple_fs.
+ */
+struct simple_fs *simple_new (const struct simple_node *node_list);
+
+#endif /* SIMPLE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/simple_hello.c	Fri Sep 26 20:11:22 2008 +0300
@@ -0,0 +1,71 @@
+
+#include <event2/event.h>
+
+#include "lib/log.h"
+#include "lib/signals.h"
+#include "evfuse.h"
+#include "simple.h"
+
+static struct hello {
+    struct event_base *ev_base;
+
+    struct signals *signals;
+
+    struct simple_fs *fs;
+
+    struct evfuse *ev_fuse;
+
+} ctx;
+
+static struct simple_node node_list[] = {
+    {   1,  S_IFDIR,    0555,   0,  NULL,       NULL                },
+    {   2,  S_IFREG,    0444,   1,  "hello",    "Hello World!\n"    },
+    {   0,  0,          0,      0,  NULL,       NULL                },
+};
+
+int main (int argc, char **argv) {
+    struct fuse_args fuse_args = FUSE_ARGS_INIT(argc, argv);
+    
+    // init libevent
+    if ((ctx.ev_base = event_base_new()) == NULL)
+        ERROR("event_base_new");
+    
+    // setup signals
+    if ((ctx.signals = signals_default(ctx.ev_base)) == NULL)
+        ERROR("signals_default");
+    
+    // setup fs
+    if ((ctx.fs = simple_new(node_list)) == NULL)
+        ERROR("simple_new");
+
+    // open fuse
+    if ((ctx.ev_fuse = evfuse_new(ctx.ev_base, &fuse_args, simple_init(), ctx.fs)) == NULL)
+        ERROR("evfuse_new");
+
+    // run libevent
+    INFO("running libevent loop");
+
+    if (event_base_dispatch(ctx.ev_base))
+        PERROR("event_base_dispatch");
+    
+    // clean shutdown
+
+error :
+    // cleanup
+    if (ctx.ev_fuse)
+        evfuse_close(ctx.ev_fuse);
+
+/*
+    if (ctx.fs)
+        simple_close(ctx.fs);
+*/
+
+    if (ctx.signals)
+        signals_free(ctx.signals);
+
+    if (ctx.ev_base)
+        event_base_free(ctx.ev_base);
+    
+    fuse_opt_free_args(&fuse_args);
+}
+