/* $Id$ * client FUSE interface for libcaptive * Copyright (C) 2005 Jan Kratochvil * * 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 #include #include #include #include #include #include #include #include #include #include "main.h" /* self */ #include "op_statfs.h" #include "op_fsync.h" #include "op_fsyncdir.h" #include "op_opendir.h" #include "op_readdir.h" #include "op_releasedir.h" #include "op_open.h" #include "op_read.h" #include "op_release.h" #include "op_getattr.h" #include "op_mknod.h" #include "op_unlink.h" #include "op_mkdir.h" #include "op_rmdir.h" #include "op_chmod.h" #include "op_truncate.h" #include "op_write.h" #include "op_rename.h" #include "op_utime.h" /* Config: */ /* FIXME: Dupe with libcaptive/client/options.c */ #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON /* Each element must be preceded by a comma (',')! */ #define LIBFUSE_ADDONS ",default_permissions,kernel_cache" 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, opendir: op_opendir, readdir: op_readdir, releasedir: op_releasedir, open: op_open, read: op_read, release: op_release, getattr: op_getattr, mknod: op_mknod, unlink: op_unlink, mkdir: op_mkdir, rmdir: op_rmdir, chmod: op_chmod, truncate: op_truncate, write: op_write, rename: op_rename, utime: op_utime, }; /* 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)) { /* Do not: g_error(_("FUSE fuse_loop() error")); * as it is caused on each umount(8). * FIXME: Why? */ } fuse_teardown(capfuse_fuse,capfuse_fd,capfuse_mountpoint); } int main(int argc,char **argv) { poptContext context; int errint; int rest_argc,i; const char **rest_argv,**csp; struct captive_options options; const char **capfuse_argv; const char *program_name=argv[0]; const char *sandbox_server_argv0=G_STRINGIFY(LIBEXECDIR) "/captive-sandbox-server"; const char *image_filename; g_log_set_always_fatal(~(0 |G_LOG_LEVEL_MESSAGE |G_LOG_LEVEL_INFO |G_LOG_LEVEL_DEBUG )); captive_standalone_init(); captive_options_init(&options); captive_options=&options; /* for parsing by 'CAPTIVE_POPT_INCLUDE' */ g_assert(!options.sandbox_server_argv); g_assert(!options.sandbox_server_ior); /* captive_options_free(&options) will: g_free(options.sandbox_server_argv); */ /* Allocation is so terrible to be compatible with: captive_options_copy() */ options.sandbox_server_argv=g_malloc(2*sizeof(*options.sandbox_server_argv)+strlen(sandbox_server_argv0)+1); options.sandbox_server_argv[0]=(char *)(options.sandbox_server_argv+2); options.sandbox_server_argv[1]=NULL; strcpy(options.sandbox_server_argv[0],sandbox_server_argv0); options.sandbox=TRUE; g_assert(!options.bug_pathname); options.bug_pathname=g_strdup(G_STRINGIFY(VARLIBCAPTIVEDIR) "/bug-%FT%T.captivebug.xml.gz"); options.syslog_facility=DEFAULT_SYSLOG_FACILITY; 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++; /* Override the (default) Captive options with mount(8) supplied "-o" argument. */ /* rest_argv[0] is the device now. */ /* rest_argv[1] is the mountpoint now. */ if (rest_argc>=4 && !strcmp(rest_argv[2],"-o")) { const char *cs=rest_argv[3]; while (cs&&*cs) { if ((!strncmp(cs,"ro",2) || !strncmp(cs,"rw",2)) && (cs[2]==',' || !cs[2])) { if (!strncmp(cs,"ro",2)) options.rwmode=CAPTIVE_OPTION_RWMODE_RO; if (!strncmp(cs,"rw",2)) options.rwmode=CAPTIVE_OPTION_RWMODE_RW; } if ((cs=strchr(cs,','))) cs++; } } /* 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); image_filename=rest_argv[0]; rest_argc--; rest_argv++; if (!(options.image_iochannel=g_io_channel_new_file( image_filename, /* filename */ (options.rwmode==CAPTIVE_OPTION_RWMODE_RW ? "r+" : "r"), /* mode */ NULL))) { /* error */ g_error(_("image_iochannel failed open of: %s"),image_filename); return EXIT_FAILURE; } if (!options.captivemodid) options.captivemodid=captive_captivemodid_load_default(FALSE); if (options.filesystem.type==CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY) { const char *self_prefix="mount.captive-"; size_t self_prefix_len=strlen(self_prefix); const char *fsname; if ((fsname=strrchr(program_name,'/'))) fsname++; else fsname=program_name; if (strncmp(fsname,self_prefix,self_prefix_len)) g_error(_("Cannot detected default filesystem name from my basename: %s"),fsname); fsname+=self_prefix_len; if (!captive_options_module_load(&options.filesystem, captive_printf_alloca("%s/%s.sys",G_STRINGIFY(VARLIBCAPTIVEDIR),fsname))) g_error(_("'--filesystem' option requires valid pathname ('ntfs.sys' suggested)")); g_assert(options.filesystem.type!=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY); } if (!options.load_module) { struct captive_options_module *options_module; captive_new(options_module); if (!captive_options_module_load(options_module,G_STRINGIFY(VARLIBCAPTIVEDIR) "/ntoskrnl.exe")) g_error(_("'--load-module' option requires valid pathname ('ntoskrnl.exe' suggested)")); options.load_module=g_list_append(options.load_module,options_module); } /* It is still required for: captive_options_module_load() */ captive_options=NULL; /* already parsed by 'CAPTIVE_POPT_INCLUDE' */ 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); /* Simulate argv[0] there as it got cut by popt. */ captive_newn_alloca(capfuse_argv,1+rest_argc+1+2); capfuse_argv[0]=argv[0]; memcpy(capfuse_argv+1,rest_argv,sizeof(*rest_argv)*(rest_argc+1)); for (i=1;capfuse_argv[i];i++) { if (strcmp(capfuse_argv[i],"-o")) continue; capfuse_argv[i+1]=captive_printf_alloca("fsname=%s" LIBFUSE_ADDONS ",%s",image_filename,capfuse_argv[i+1]); break; } if (!capfuse_argv[i]) { capfuse_argv[i ]="-o"; capfuse_argv[i+1]=captive_printf_alloca("fsname=%s" LIBFUSE_ADDONS,image_filename); capfuse_argv[i+2]=NULL; } /* 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; }