#!/usr/bin/env python import sys import subprocess def main(): opts = sys.argv[2:] repo = sys.argv[1] cmd = ['/usr/bin/tagsistant', '--repository=' + repo] cmd.extend(opts) subprocess.call(cmd) if __name__ == '__main__': main()
Saving this wrapper as /usr/bin/tagfs, a user can mount a Tagsistant repository from /etc/fstab with a line such:
tagfs#/path/to/repository /path/to/mountpoint fuse noatime,user,allow_other 0 0
Hunting memory leaks, I've faced the problem of using Valgrind on a FUSE filesysem. Since fusermount is a SUIDed executable, Valgrind somehow interfere with filesystem mounting.
Here is a solution I've found searching on the Net:
# cd /usr/bin
# if [[ -e fusermount ]]; then mv fusermount fusermount.real; fi
# touch fusermount
# chown root.fuse fusermount
# chmod ug+x fusermount
# echo '#!/bin/sh' >> fusermount
# echo 'exec /usr/bin/fusermount.real $@' >> fusermount
[ or depending on the path of fusermount ]
# echo 'exec /bin/fusermount $@' >> fusermount
The original resource about that is available here
Tagsistant uses dlopen() suite of functions to include external components. Mainly, Tagsistant uses external plugins to implement auto-tagging. Each plugin registers a MIME-type and is then called during a stack walking procedure to give it the opportunity of managing data. The plugin can then return a code meaning "I've done!" or "Some other plugin can add more action for this file" or "I've no chance to do anything on that!".
Let's see how is structured a plugin using the HTML plugin as a reference.
#include "tagsistant.h"
#define DEFAULT_TAG "document"
/* declaring mime type */
char mime_type[] = "text/html";
First of all, import tagsistant.h to have all the symbols available. Then define a preprocessor macro DEFAULT_TAG with the tag the files will be tagged as, and a string called mime_type which describes the exact MIME-type, like in text/html.
/* exported init function */
int plugin_init()
{
return 1;
}
/* exported finalize function */
void plugin_free()
{
}
The plugin_init() function is used by tagsistant while loading the plugin to execute some code that needs to be initialized, like calling a library entry point or creating some dynamic structures in memory.
Easy to guess, plugin_free() is the opposite. It's called on program exit to unregister other code, free memory and clean up.
/* exported processor function */
int processor(const tagsistant_querytree *qtree)
{
dbg(LOG_INFO, "Taggings %s as %s", filename, DEFAULT_TAG);
tagsistant_sql_tag_object(qtree->dbi, DEFAULT_TAG, qtree->inode);
tagsistant_sql_tag_object(qtree->dbi, "another_tag", qtree->inode);
return TP_STOP;
}
processor() function is the hook Tagsistant registers to later call the plugin during stack walking. It just receives the path of the file as first argument. As you can see, many symbols are available to plugins. You can use dbg(level, format, ...) macro to send lines to syslog or stderr. To tag files, you must use the Tagsistant function tag_file(filename, tagname) which accepts the file name as first argument (char *) and the tag as second argument (also char *).
Pay attention in returning a meaningful value. The available values can be found in tagsistant.h, and are:
#define TP_ERROR 0 /* an error occurred while processing with this plugin */
#define TP_OK 1 /* ok, but further tagging can be done by other plugins */
#define TP_STOP 2 /* this plugin is authoritative for mimetype, stop chaining */
#define TP_NULL 3 /* no tagging has been done, but that is not an error */
Defining a preprocessor symbol called DEFAULT_TAG is not mandatory, since all the occurrences will be inside processor() function, but will make plugin understanding a lot easier, by locating on its top the tag that the plugin creates.
I've started porting Tagsistant under MacOS X. Porting GNU/Linux software to MacOS X requires some steps. Hopefully, GNU environment is available from many sources. I've personally used Fink. Follow the instructions on their site to install the packages needed.
Some useful functions from GNU libc (getline() and strndup()) are not available with MacOS X. So I've replaced them. It's a quick patch, using a MACOSX preprocessor symbol to guess if handmade replacements should be compiled. I'm not happy with that. More proper function existence check should be performed to replace those function even on other platforms.
Fink provides SQLite package, but for FUSE you need a special port, since this package directly interacts with the kernel. This port is called MacFUSE and is located here. Install version 10.5-1.3.1 (Leopard is the platform available to me).
Tagsistant compiles fine under MacOS X but has a problem with mknod() calls. Probably that's due to the fact that archive/ directory, where files are really located, is outside the mountpoint. Or may be it's due to other reason. So far, creating a file inside Tagsistant will result in a permission denied error.
If someone wants to help with that, please drop me a mail.