/* $Id$ * User options handling code of libcaptive * Copyright (C) 2003 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 "captive/options.h" /* self */ #include #include "captive/macros.h" #include #include #include /* Config: */ #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON void captive_options_init(struct captive_options *options) { g_return_if_fail(options!=NULL); CAPTIVE_MEMZERO(options); options->filesystem.type=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY; options->rwmode=CAPTIVE_OPTION_RWMODE_BLIND; options->media=CAPTIVE_OPTION_MEDIA_DISK; options->debug_messages=FALSE; options->load_module=NULL; options->sandbox=FALSE; options->syslog_facility=-1; } void captive_options_copy(struct captive_options *dest,const struct captive_options *src) { GList *load_module_node; g_return_if_fail(dest!=NULL); g_return_if_fail(src!=NULL); g_return_if_fail(dest!=src); memcpy(dest,src,sizeof(*dest)); captive_options_module_copy(&dest->filesystem,&src->filesystem); if (dest->image_iochannel) g_io_channel_ref(dest->image_iochannel); dest->load_module=NULL; for (load_module_node=src->load_module;load_module_node;load_module_node=load_module_node->next) { struct captive_options_module *options_module_src=load_module_node->data; struct captive_options_module *options_module_dest; captive_new(options_module_dest); captive_options_module_copy(options_module_dest,options_module_src); dest->load_module=g_list_append(dest->load_module,options_module_dest); } if (src->sandbox_server_argv) { char **sp; for (sp=src->sandbox_server_argv;*sp;sp++) { if (sp>src->sandbox_server_argv) g_assert(*sp>=sp[-1]); } dest->sandbox_server_argv=g_memdup(src->sandbox_server_argv, (sp==src->sandbox_server_argv ? (char *)(sp+1) : sp[-1]+strlen(sp[-1])+1) - (char *)src->sandbox_server_argv); /* Really update the pointers inside the copied array block. :-) */ for (sp=src->sandbox_server_argv;*sp;sp++) { dest->sandbox_server_argv[sp-src->sandbox_server_argv]=(gpointer)((char *)dest->sandbox_server_argv +(src->sandbox_server_argv[sp-src->sandbox_server_argv]-(char *)src->sandbox_server_argv)); } } if (src->sandbox_server_ior) dest->sandbox_server_ior=g_strdup(src->sandbox_server_ior); if (src->bug_pathname) dest->bug_pathname=g_strdup(src->bug_pathname); } void captive_options_free(struct captive_options *options) { g_return_if_fail(options!=NULL); captive_options_module_free(&options->filesystem); if (options->image_iochannel) g_io_channel_unref(options->image_iochannel); while (options->load_module) { captive_options_module_free(options->load_module->data); options->load_module=g_list_delete_link(options->load_module,options->load_module); /* also frees 'options->load_module->data' */ } g_free(options->sandbox_server_argv); g_free(options->sandbox_server_ior); g_free(options->bug_pathname); } static gchar *captive_popt_optarg; static void arg_filesystem(void) { gboolean errbool; captive_options_module_free(&captive_options->filesystem); errbool=captive_options_module_load(&captive_options->filesystem,captive_popt_optarg); g_assert(errbool==TRUE); } static void arg_load_module(void) { struct captive_options_module *options_module; gboolean errbool; captive_new(options_module); errbool=captive_options_module_load(options_module,captive_popt_optarg); g_assert(errbool==TRUE); captive_options->load_module=g_list_append(captive_options->load_module,options_module); } static void arg_ro(void) { captive_options->rwmode=CAPTIVE_OPTION_RWMODE_RO; } static void arg_blind(void) { captive_options->rwmode=CAPTIVE_OPTION_RWMODE_BLIND; } static void arg_rw(void) { captive_options->rwmode=CAPTIVE_OPTION_RWMODE_RW; } static void arg_cdrom(void) { captive_options->media=CAPTIVE_OPTION_MEDIA_CDROM; } static void arg_disk(void) { captive_options->media=CAPTIVE_OPTION_MEDIA_DISK; } static void arg_debug_messages(void) { captive_options->debug_messages=TRUE; } static void sandbox_args_clear(void) { free(captive_options->sandbox_server_argv); captive_options->sandbox_server_argv=NULL; g_free(captive_options->sandbox_server_ior); captive_options->sandbox_server_ior=NULL; captive_options->sandbox=FALSE; } static void arg_sandbox_server(void) { int errint; int trash_argc; sandbox_args_clear(); /* 'argcPtr' is forbidden to be NULL at least by popt of rpm-3.0.6. */ errint=poptParseArgvString( captive_popt_optarg, /* s */ &trash_argc, /* argcPtr */ (const char ***)&captive_options->sandbox_server_argv); /* argvPtr */ g_assert(errint==0); captive_options->sandbox=TRUE; } static void arg_sandbox_server_ior(void) { sandbox_args_clear(); captive_options->sandbox_server_ior=g_strdup(captive_popt_optarg); captive_options->sandbox=TRUE; } static void arg_no_sandbox(void) { sandbox_args_clear(); } static void arg_bug_pathname(void) { g_free(captive_options->bug_pathname); captive_options->bug_pathname=g_strdup(captive_popt_optarg); } /* Do not: #define SYSLOG_NAMES 1 * to enable /facilitynames[] as such array is global (non-static) * and it is likely it would conflict with facilitynames[] defined elsewhere * (such as even conflicts by libcaptive.so). */ static const struct syslog_facility { const gchar *name; int value; } syslog_facility[]={ #ifdef LOG_AUTHPRIV { "authpriv", LOG_AUTHPRIV }, #endif #ifdef LOG_CRON { "cron" , LOG_CRON }, #endif #ifdef LOG_DAEMON { "daemon" , LOG_DAEMON }, #endif #ifdef LOG_FTP { "ftp" , LOG_FTP }, #endif #ifdef LOG_KERN { "kern" , LOG_KERN }, #endif #ifdef LOG_LPR { "lpr" , LOG_LPR }, #endif #ifdef LOG_MAIL { "mail" , LOG_MAIL }, #endif #ifdef LOG_NEWS { "news" , LOG_NEWS }, #endif #ifdef LOG_SYSLOG { "syslog" , LOG_SYSLOG }, #endif #ifdef LOG_USER { "user" , LOG_USER }, #endif #ifdef LOG_UUCP { "uucp" , LOG_UUCP }, #endif #ifdef LOG_LOCAL0 { "local0" , LOG_LOCAL0 }, #endif #ifdef LOG_LOCAL1 { "local1" , LOG_LOCAL1 }, #endif #ifdef LOG_LOCAL2 { "local2" , LOG_LOCAL2 }, #endif #ifdef LOG_LOCAL3 { "local3" , LOG_LOCAL3 }, #endif #ifdef LOG_LOCAL4 { "local4" , LOG_LOCAL4 }, #endif #ifdef LOG_LOCAL5 { "local5" , LOG_LOCAL5 }, #endif #ifdef LOG_LOCAL6 { "local6" , LOG_LOCAL6 }, #endif #ifdef LOG_LOCAL7 { "local7" , LOG_LOCAL7 }, #endif }; static void arg_syslog(void) { captive_options->syslog_facility=DEFAULT_SYSLOG_FACILITY; } static int arg_syslog_facility_value; static void arg_syslog_facility(void) { const struct syslog_facility *facility; GString *gstring; gchar *gs; for (facility=syslog_facility;facilityname)) { arg_syslog_facility_value=facility->value; return; } gstring=g_string_new(captive_printf_alloca(_("Unknown '--syslog' facility '%s'; known:"),captive_popt_optarg)); for (facility=syslog_facility;facilityname); } gs=g_string_free(gstring, FALSE); /* free_segment */ g_warning(gs); g_free(gs); } static void captive_popt_callback (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data); const struct poptOption captive_popt[]={ { argInfo:POPT_ARG_INTL_DOMAIN,arg:(void *)PACKAGE }, { argInfo:POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,arg:(void *)captive_popt_callback }, #define POPT_OFFSET 2 #define CAPTIVE_POPT(longname,argInfoP,argP,descripP,argDescripP) \ { \ longName: (longname), \ shortName: 0, \ argInfo: (argInfoP), \ arg: (void *)argP, \ val: 0, \ descrip: (descripP), \ argDescrip: (argDescripP), \ } #define CAPTIVE_POPT_STRING(longname,descripP,argDescripP) \ CAPTIVE_POPT(longname,POPT_ARG_STRING,&captive_popt_optarg,descripP,argDescripP) #define CAPTIVE_POPT_NONE(longname,descripP) \ CAPTIVE_POPT(longname,POPT_ARG_NONE ,NULL ,descripP,NULL ) CAPTIVE_POPT_STRING("filesystem" ,N_("Pathname to .sys or .so filesystem module file"),N_("pathname")), CAPTIVE_POPT_STRING("load-module" ,N_("Pathname to any W32 module to load w/o initialization"),N_("pathname")), CAPTIVE_POPT_NONE( "ro" ,N_("Read/write mode: Any write access will be forbidden")), CAPTIVE_POPT_NONE( "blind" ,N_("Read/write mode: All writes are just simulated in memory (default)")), CAPTIVE_POPT_NONE( "rw" ,N_("Read/write mode: Write directly to the image file/device")), CAPTIVE_POPT_NONE( "cdrom" ,N_("Media type: CD-ROM")), CAPTIVE_POPT_NONE( "disk" ,N_("Media type: Disk (default)")), CAPTIVE_POPT_NONE( "debug-messages" ,N_("Turn on debugging messages")), CAPTIVE_POPT_STRING("sandbox-server" ,N_("Pathname to 'captive-sandbox-server', turns on sandboxing"),N_("pathname")), CAPTIVE_POPT_STRING("sandbox-server-ior",N_("CORBA IOR of 'captive-sandbox-server', turns on sandboxing"),N_("IOR")), CAPTIVE_POPT_NONE( "no-sandbox" ,N_("Turn off sandboxing feature")), CAPTIVE_POPT_STRING("bug-pathname" ,N_("Pathname to strftime(3) for .captivebug.xml.gz bugreports"),N_("pathname")), /* Do not: POPT_ARGFLAG_OPTIONAL * as it always eats one argument unless it is at end of argv[]. */ CAPTIVE_POPT_NONE( "syslog" ,N_("Messages sent to syslog(3) instead of stderr")), CAPTIVE_POPT_STRING("syslog-facility" ,N_("openlog(3) facility for --syslog"),N_("facility")), #undef CAPTIVE_POPT_NONE #undef CAPTIVE_POPT_STRING #undef CAPTIVE_POPT POPT_TABLEEND }; static const struct poptOption captive_popt_standalone[]={ CAPTIVE_POPT_INCLUDE, POPT_AUTOHELP POPT_TABLEEND }; static void (*const popt_func_table[])(void)={ arg_filesystem, arg_load_module, arg_ro, arg_blind, arg_rw, arg_cdrom, arg_disk, arg_debug_messages, arg_sandbox_server, arg_sandbox_server_ior, arg_no_sandbox, arg_bug_pathname, arg_syslog, arg_syslog_facility, }; /* poptCallbackType captive_popt_callback */ static void captive_popt_callback (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data) { gint funci; switch (reason) { case POPT_CALLBACK_REASON_PRE: arg_syslog_facility_value=-1; break; case POPT_CALLBACK_REASON_OPTION: funci=(opt-(captive_popt+POPT_OFFSET)); g_return_if_fail(funci>=0); g_return_if_fail(funci<(gint)G_N_ELEMENTS(popt_func_table)); if (popt_func_table[funci]) (*popt_func_table[funci])(); free(captive_popt_optarg); break; case POPT_CALLBACK_REASON_POST: if (captive_options->syslog_facility!=-1 && arg_syslog_facility_value!=-1) captive_options->syslog_facility=arg_syslog_facility_value; break; default: g_assert_not_reached(); } captive_popt_optarg=NULL; /* sanity */ } gboolean captive_options_parse(struct captive_options *options,const gchar *captive_args) { int errint; int captive_args_argc; const char **captive_args_argv=NULL; poptContext context; gboolean r=FALSE; g_return_val_if_fail(options!=NULL,FALSE); g_return_val_if_fail(captive_args!=NULL,FALSE); g_assert(captive_options==NULL); captive_options=options; errint=poptParseArgvString(captive_args,&captive_args_argc,&captive_args_argv); if (errint!=0) { g_warning("argument parsing args error: %s",captive_args); goto args_err; } context=poptGetContext( PACKAGE, /* name */ captive_args_argc,captive_args_argv, /* argc,argv */ captive_popt_standalone, /* options */ POPT_CONTEXT_KEEP_FIRST); if (context==NULL) { g_warning("argument recognization args error: %s",captive_args); goto args_err_argv; } errint=poptReadDefaultConfig(context, TRUE); /* useEnv */ if (errint!=0) { g_warning("argument recognization args error: %s",captive_args); goto args_err_context; } errint=poptGetNextOpt(context); if (errint!=-1) { g_warning("some non-callbacked argument reached: %s",captive_args); goto args_err_context; } if (poptPeekArg(context)) { g_warning("some non-option argument reached: %s",captive_args); goto args_err_context; } r=TRUE; /* success */ args_err_context: poptFreeContext(context); args_err_argv: free(captive_args_argv); /* may be NULL here */ args_err: if (!r) { captive_options=NULL; return FALSE; } g_assert(captive_options!=NULL); captive_options=NULL; return TRUE; }