+FUSE interface skeleton.
[captive.git] / src / client / fuse / main.c
diff --git a/src/client/fuse/main.c b/src/client/fuse/main.c
new file mode 100644 (file)
index 0000000..4f609c8
--- /dev/null
@@ -0,0 +1,196 @@
+/* $Id$
+ * client FUSE interface for libcaptive
+ * Copyright (C) 2005 Jan Kratochvil <project-captive@jankratochvil.net>
+ * 
+ * This program 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; exactly version 2 of June 1991 is required
+ * 
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#include "config.h"
+
+#include <fuse.h>
+#include <popt.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <captive/client-vfs.h>
+#include <captive/macros.h>
+
+#include "main.h"      /* self */
+#include "op_statfs.h"
+#include "op_fsync.h"
+#include "op_fsyncdir.h"
+
+
+CaptiveVfsObject *capfuse_captive_vfs_object;
+
+static const struct poptOption popt_table[]={
+       CAPTIVE_POPT_INCLUDE,
+       POPT_AUTOHELP
+       POPT_TABLEEND
+       };
+
+static const struct fuse_operations capfuse_operations={
+       statfs:     op_statfs,
+       fsync:      op_fsync,
+       fsyncdir:   op_fsyncdir,
+#if 0
+       getattr:    op_getattr,
+       mknod:      op_mknod,
+       mkdir:      op_mkdir,
+       unlink:     op_unlink,
+       rmdir:      op_rmdir,
+       rename:     op_rename,
+       chmod:      op_chmod,
+       truncate:   op_truncate,
+       utime:      op_utime,
+       open:       op_open,
+       read:       op_read,
+       write:      op_write,
+       flush:      op_flush,
+       release:    op_release,
+       opendir:    op_opendir,
+       readdir:    op_readdir,
+       releasedir: op_releasedir,
+#endif
+       };
+
+/* argv[0] expected as the program name. */
+/* Only options and mountpoint expected here. */
+static void capfuse_run(int argc,const char **argv)
+{
+char *capfuse_mountpoint;
+int capfuse_multithreaded,capfuse_fd;
+struct fuse *capfuse_fuse;
+
+       if (!(capfuse_fuse=fuse_setup(
+                               argc,   /* argc */
+                               (/*de-const; broken fuset_setup()*/char **)argv,        /* argv */
+                               &capfuse_operations,    /* op */
+                               sizeof(capfuse_operations),     /* op_size */
+                       &capfuse_mountpoint,    /* mountpoint */
+                       &capfuse_multithreaded, /* multithreaded */
+                       &capfuse_fd)))  /* fd */
+               g_error(_("FUSE fuse_setup() failed"));
+       if (fuse_loop(capfuse_fuse))
+               g_error(_("FUSE fuse_loop() error: %m"));
+       fuse_teardown(capfuse_fuse,capfuse_fd,capfuse_mountpoint);
+}
+
+int main(int argc,char **argv)
+{
+poptContext context;
+int errint;
+int rest_argc;
+const char **rest_argv,**csp;
+struct captive_options options;
+const char **capfuse_argv;
+
+       g_log_set_always_fatal(~(0
+                       |G_LOG_LEVEL_MESSAGE
+                       |G_LOG_LEVEL_INFO
+                       |G_LOG_LEVEL_DEBUG
+                       ));
+
+       /* Prevent output block buffering if redirecting stdout to file. */
+       setvbuf(stdout,(char *)NULL,_IONBF,0);
+       setvbuf(stderr,(char *)NULL,_IONBF,0);
+
+       /* Initialize the i18n stuff */
+       setlocale(LC_ALL,"");
+       bindtextdomain(PACKAGE,LOCALEDIR);
+       textdomain(PACKAGE);
+
+       /* Initialize GObject subsystem of GLib. */
+       g_type_init();
+
+       captive_options_init(&options);
+       captive_options=&options;       /* for parsing by 'CAPTIVE_POPT_INCLUDE' */
+
+       context=poptGetContext(
+                       PACKAGE,        /* name */
+                       argc,(/*en-const*/const char **)argv,   /* argc,argv */
+                       popt_table,     /* options */
+                       POPT_CONTEXT_POSIXMEHARDER);    /* flags; && !POPT_CONTEXT_KEEP_FIRST */
+       if (context==NULL) {
+               g_error(_("Error parsing command-line arguments"));
+               return EXIT_FAILURE;
+               }
+       errint=poptReadDefaultConfig(context,
+                       TRUE);  /* useEnv */
+       if (errint!=0)
+               g_warning(_("Error reading default popt configuration"));
+       errint=poptGetNextOpt(context);
+       if (errint!=-1) {
+               g_error(_("Error parsing (dash-prefixed) command-line argument"));
+               return EXIT_FAILURE;
+               }
+       rest_argv=poptGetArgs(context);
+       for (csp=rest_argv,rest_argc=0;csp && *csp;csp++)
+               rest_argc++;
+
+       captive_options=NULL;   /* already parsed by 'CAPTIVE_POPT_INCLUDE' */
+
+       /* image_iochannel */
+       if (rest_argc<1) {
+               g_error(_("File/device disk image pathname command-line argument required"));
+               return EXIT_FAILURE;
+               }
+       g_assert(options.image_iochannel==NULL);
+       if (!(options.image_iochannel=g_io_channel_new_file(
+                       rest_argv[0],   /* filename */
+                       (options.rwmode==CAPTIVE_OPTION_RWMODE_RW ? "r+" : "r"),        /* mode */
+                       NULL))) {       /* error */
+               g_error(_("image_iochannel open failed"));
+               return EXIT_FAILURE;
+               }
+
+       if (options.filesystem.type==CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY) {
+               g_error(_("'--filesystem' option required ('ntfs.sys' pathname suggested)"));
+               return EXIT_FAILURE;
+               }
+       if (!options.load_module) {
+               g_warning(_("'--load-module' option required ('ntoskrnl.exe' pathname suggested)"));
+               return EXIT_FAILURE;
+               }
+
+       if (GNOME_VFS_OK!=captive_vfs_new(&capfuse_captive_vfs_object,&options)) {
+               g_error(_("captive_vfs_new() failed"));
+               return EXIT_FAILURE;
+               }
+       captive_options_free(&options);
+       rest_argc--;
+       rest_argv++;
+
+       /* Simulate argv[0] there as it got cut by popt. */
+       captive_newn_alloca(capfuse_argv,1+rest_argc+1);
+       capfuse_argv[0]=argv[0];
+       memcpy(capfuse_argv+1,rest_argv,sizeof(*rest_argv)*(rest_argc+1));
+
+       /* FIXFUSE: fuse_main()/fuse_main_real() would be enough for Captive fuse but
+        * the public interface of fuse_main() is too broken.
+        */
+       capfuse_run(1+rest_argc,capfuse_argv);
+
+       /* 'rest_argv' gets cleared by 'poptFreeContext(context);' below */
+       poptFreeContext(context);
+
+       if (capfuse_captive_vfs_object) {
+               g_object_unref(capfuse_captive_vfs_object);
+               capfuse_captive_vfs_object=NULL;
+               }
+
+       return EXIT_SUCCESS;
+}