Limit maximum number of SharedCacheMap mapped objects.
[captive.git] / src / libcaptive / client / options.c
1 /* $Id$
2  * User options handling code of libcaptive
3  * Copyright (C) 2003 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "captive/options.h"    /* self */
23 #include <glib/gmessages.h>
24 #include "captive/macros.h"
25 #include <glib/gstrfuncs.h>
26 #include <stdlib.h>
27 #include <syslog.h>
28
29
30 /* Config: */
31 #define DEFAULT_SYSLOG_FACILITY LOG_DAEMON
32
33
34 void captive_options_init(struct captive_options *options)
35 {
36         g_return_if_fail(options!=NULL);
37
38         CAPTIVE_MEMZERO(options);
39         options->filesystem.type=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY;
40         options->rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
41         options->media=CAPTIVE_OPTION_MEDIA_DISK;
42         options->debug_messages=FALSE;
43         options->load_module=NULL;
44         options->sandbox=FALSE;
45         options->syslog_facility=-1;
46 }
47
48
49 void captive_options_copy(struct captive_options *dest,const struct captive_options *src)
50 {
51 GList *load_module_node;
52
53         g_return_if_fail(dest!=NULL);
54         g_return_if_fail(src!=NULL);
55         g_return_if_fail(dest!=src);
56
57         memcpy(dest,src,sizeof(*dest));
58
59         captive_options_module_copy(&dest->filesystem,&src->filesystem);
60         if (dest->image_iochannel)
61                 g_io_channel_ref(dest->image_iochannel);
62
63         dest->load_module=NULL;
64         for (load_module_node=src->load_module;load_module_node;load_module_node=load_module_node->next) {
65 struct captive_options_module *options_module_src=load_module_node->data;
66 struct captive_options_module *options_module_dest;
67
68                 captive_new(options_module_dest);
69                 captive_options_module_copy(options_module_dest,options_module_src);
70                 dest->load_module=g_list_append(dest->load_module,options_module_dest);
71                 }
72
73         if (src->sandbox_server_argv) {
74 char **sp;
75
76                 for (sp=src->sandbox_server_argv;*sp;sp++) {
77                         if (sp>src->sandbox_server_argv)
78                                 g_assert(*sp>=sp[-1]);
79                         }
80                 dest->sandbox_server_argv=g_memdup(src->sandbox_server_argv,
81                                 (sp==src->sandbox_server_argv ? (char *)(sp+1) : sp[-1]+strlen(sp[-1])+1) - (char *)src->sandbox_server_argv);
82                 /* Really update the pointers inside the copied array block. :-) */
83                 for (sp=src->sandbox_server_argv;*sp;sp++) {
84                         dest->sandbox_server_argv[sp-src->sandbox_server_argv]=(gpointer)((char *)dest->sandbox_server_argv
85                                                         +(src->sandbox_server_argv[sp-src->sandbox_server_argv]-(char *)src->sandbox_server_argv));
86                         }
87                 }
88
89         if (src->sandbox_server_ior)
90                 dest->sandbox_server_ior=g_strdup(src->sandbox_server_ior);
91
92         if (src->bug_pathname)
93                 dest->bug_pathname=g_strdup(src->bug_pathname);
94 }
95
96
97 void captive_options_free(struct captive_options *options)
98 {
99         g_return_if_fail(options!=NULL);
100
101         captive_options_module_free(&options->filesystem);
102         if (options->image_iochannel)
103                 g_io_channel_unref(options->image_iochannel);
104
105         while (options->load_module) {
106                 captive_options_module_free(options->load_module->data);
107                 options->load_module=g_list_delete_link(options->load_module,options->load_module);     /* also frees 'options->load_module->data' */
108                 }
109
110         g_free(options->sandbox_server_argv);
111         g_free(options->sandbox_server_ior);
112         g_free(options->bug_pathname);
113 }
114
115
116 static gchar *captive_popt_optarg;
117
118
119 static void arg_filesystem(void)
120 {
121 gboolean errbool;
122
123         captive_options_module_free(&captive_options->filesystem);
124         errbool=captive_options_module_load(&captive_options->filesystem,captive_popt_optarg);
125         g_assert(errbool==TRUE);
126 }
127
128 static void arg_load_module(void)
129 {
130 struct captive_options_module *options_module;
131 gboolean errbool;
132
133         captive_new(options_module);
134         errbool=captive_options_module_load(options_module,captive_popt_optarg);
135         g_assert(errbool==TRUE);
136
137         captive_options->load_module=g_list_append(captive_options->load_module,options_module);
138 }
139
140 static void arg_ro(void)
141 {
142         captive_options->rwmode=CAPTIVE_OPTION_RWMODE_RO;
143 }
144 static void arg_blind(void)
145 {
146         captive_options->rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
147 }
148 static void arg_rw(void)
149 {
150         captive_options->rwmode=CAPTIVE_OPTION_RWMODE_RW;
151 }
152
153 static void arg_cdrom(void)
154 {
155         captive_options->media=CAPTIVE_OPTION_MEDIA_CDROM;
156 }
157 static void arg_disk(void)
158 {
159         captive_options->media=CAPTIVE_OPTION_MEDIA_DISK;
160 }
161
162 static void arg_debug_messages(void)
163 {
164         captive_options->debug_messages=TRUE;
165 }
166
167 static void sandbox_args_clear(void)
168 {
169         free(captive_options->sandbox_server_argv);
170         captive_options->sandbox_server_argv=NULL;
171
172         g_free(captive_options->sandbox_server_ior);
173         captive_options->sandbox_server_ior=NULL;
174
175         captive_options->sandbox=FALSE;
176 }
177
178 static void arg_sandbox_server(void)
179 {
180 int errint;
181 int trash_argc;
182
183         sandbox_args_clear();
184
185         /* 'argcPtr' is forbidden to be NULL at least by popt of rpm-3.0.6. */
186         errint=poptParseArgvString(
187                         captive_popt_optarg,    /* s */
188                         &trash_argc,    /* argcPtr */
189                         (const char ***)&captive_options->sandbox_server_argv); /* argvPtr */
190         g_assert(errint==0);
191
192         captive_options->sandbox=TRUE;
193 }
194
195 static void arg_sandbox_server_ior(void)
196 {
197         sandbox_args_clear();
198
199         captive_options->sandbox_server_ior=g_strdup(captive_popt_optarg);
200         captive_options->sandbox=TRUE;
201 }
202
203 static void arg_no_sandbox(void)
204 {
205         sandbox_args_clear();
206 }
207
208 static void arg_bug_pathname(void)
209 {
210         g_free(captive_options->bug_pathname);
211         captive_options->bug_pathname=g_strdup(captive_popt_optarg);
212 }
213
214 /* Do not: #define SYSLOG_NAMES 1
215  * to enable <syslog.h>/facilitynames[] as such array is global (non-static)
216  * and it is likely it would conflict with facilitynames[] defined elsewhere
217  * (such as even conflicts by libcaptive.so).
218  */
219 static const struct syslog_facility {
220         const gchar *name;
221         int value;
222         } syslog_facility[]={
223 #ifdef LOG_AUTHPRIV
224                 { "authpriv", LOG_AUTHPRIV },
225 #endif
226 #ifdef LOG_CRON
227                 { "cron"    , LOG_CRON },
228 #endif
229 #ifdef LOG_DAEMON
230                 { "daemon"  , LOG_DAEMON },
231 #endif
232 #ifdef LOG_FTP
233                 { "ftp"     , LOG_FTP },
234 #endif
235 #ifdef LOG_KERN
236                 { "kern"    , LOG_KERN },
237 #endif
238 #ifdef LOG_LPR
239                 { "lpr"     , LOG_LPR },
240 #endif
241 #ifdef LOG_MAIL
242                 { "mail"    , LOG_MAIL },
243 #endif
244 #ifdef LOG_NEWS
245                 { "news"    , LOG_NEWS },
246 #endif
247 #ifdef LOG_SYSLOG
248                 { "syslog"  , LOG_SYSLOG },
249 #endif
250 #ifdef LOG_USER
251                 { "user"    , LOG_USER },
252 #endif
253 #ifdef LOG_UUCP
254                 { "uucp"    , LOG_UUCP },
255 #endif
256 #ifdef LOG_LOCAL0
257                 { "local0"  , LOG_LOCAL0 },
258 #endif
259 #ifdef LOG_LOCAL1
260                 { "local1"  , LOG_LOCAL1 },
261 #endif
262 #ifdef LOG_LOCAL2
263                 { "local2"  , LOG_LOCAL2 },
264 #endif
265 #ifdef LOG_LOCAL3
266                 { "local3"  , LOG_LOCAL3 },
267 #endif
268 #ifdef LOG_LOCAL4
269                 { "local4"  , LOG_LOCAL4 },
270 #endif
271 #ifdef LOG_LOCAL5
272                 { "local5"  , LOG_LOCAL5 },
273 #endif
274 #ifdef LOG_LOCAL6
275                 { "local6"  , LOG_LOCAL6 },
276 #endif
277 #ifdef LOG_LOCAL7
278                 { "local7"  , LOG_LOCAL7 },
279 #endif
280         };
281
282 static void arg_syslog(void)
283 {
284         captive_options->syslog_facility=DEFAULT_SYSLOG_FACILITY;
285 }
286
287 static int arg_syslog_facility_value;
288
289 static void arg_syslog_facility(void)
290 {
291 const struct syslog_facility *facility;
292 GString *gstring;
293 gchar *gs;
294
295         for (facility=syslog_facility;facility<syslog_facility+G_N_ELEMENTS(syslog_facility);facility++)
296                 if (!strcmp(captive_popt_optarg,facility->name)) {
297                         arg_syslog_facility_value=facility->value;
298                         return;
299                         }
300
301         gstring=g_string_new(captive_printf_alloca(_("Unknown '--syslog' facility '%s'; known:"),captive_popt_optarg));
302         for (facility=syslog_facility;facility<syslog_facility+G_N_ELEMENTS(syslog_facility);facility++) {
303                 gstring=g_string_append_c(gstring,' ');
304                 gstring=g_string_append(gstring,facility->name);
305                 }
306         gs=g_string_free(gstring,
307                         FALSE); /* free_segment */
308         g_warning(gs);
309         g_free(gs);
310 }
311
312
313 static void captive_popt_callback
314                 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data);
315
316 const struct poptOption captive_popt[]={
317                 { argInfo:POPT_ARG_INTL_DOMAIN,arg:(void *)PACKAGE },
318                 { argInfo:POPT_ARG_CALLBACK|POPT_CBFLAG_PRE|POPT_CBFLAG_POST,arg:(void *)captive_popt_callback },
319 #define POPT_OFFSET 2
320 #define CAPTIVE_POPT(longname,argInfoP,argP,descripP,argDescripP) \
321                 { \
322                         longName: (longname), \
323                         shortName: 0, \
324                         argInfo: (argInfoP), \
325                         arg: (void *)argP, \
326                         val: 0, \
327                         descrip: (descripP), \
328                         argDescrip: (argDescripP), \
329                 }
330 #define CAPTIVE_POPT_STRING(longname,descripP,argDescripP) \
331                 CAPTIVE_POPT(longname,POPT_ARG_STRING,&captive_popt_optarg,descripP,argDescripP)
332 #define CAPTIVE_POPT_NONE(longname,descripP) \
333                 CAPTIVE_POPT(longname,POPT_ARG_NONE  ,NULL                ,descripP,NULL       )
334
335                 CAPTIVE_POPT_STRING("filesystem"        ,N_("Pathname to .sys or .so filesystem module file"),N_("pathname")),
336                 CAPTIVE_POPT_STRING("load-module"       ,N_("Pathname to any W32 module to load w/o initialization"),N_("pathname")),
337                 CAPTIVE_POPT_NONE(  "ro"                ,N_("Read/write mode: Any write access will be forbidden")),
338                 CAPTIVE_POPT_NONE(  "blind"             ,N_("Read/write mode: All writes are just simulated in memory (default)")),
339                 CAPTIVE_POPT_NONE(  "rw"                ,N_("Read/write mode: Write directly to the image file/device")),
340                 CAPTIVE_POPT_NONE(  "cdrom"             ,N_("Media type: CD-ROM")),
341                 CAPTIVE_POPT_NONE(  "disk"              ,N_("Media type: Disk (default)")),
342                 CAPTIVE_POPT_NONE(  "debug-messages"    ,N_("Turn on debugging messages")),
343                 CAPTIVE_POPT_STRING("sandbox-server"    ,N_("Pathname to 'captive-sandbox-server', turns on sandboxing"),N_("pathname")),
344                 CAPTIVE_POPT_STRING("sandbox-server-ior",N_("CORBA IOR of 'captive-sandbox-server', turns on sandboxing"),N_("IOR")),
345                 CAPTIVE_POPT_NONE(  "no-sandbox"        ,N_("Turn off sandboxing feature")),
346                 CAPTIVE_POPT_STRING("bug-pathname"      ,N_("Pathname to strftime(3) for .captivebug.xml.gz bugreports"),N_("pathname")),
347                 /* Do not: POPT_ARGFLAG_OPTIONAL
348                  * as it always eats one argument unless it is at end of argv[].
349                  */
350                 CAPTIVE_POPT_NONE(  "syslog"            ,N_("Messages sent to syslog(3) instead of stderr")),
351                 CAPTIVE_POPT_STRING("syslog-facility"   ,N_("openlog(3) facility for --syslog"),N_("facility")),
352
353 #undef CAPTIVE_POPT_NONE
354 #undef CAPTIVE_POPT_STRING
355 #undef CAPTIVE_POPT
356                 POPT_TABLEEND
357                 };
358
359 static const struct poptOption captive_popt_standalone[]={
360                 CAPTIVE_POPT_INCLUDE,
361                 POPT_AUTOHELP
362                 POPT_TABLEEND
363                 };
364
365
366 static void (*const popt_func_table[])(void)={
367                 arg_filesystem,
368                 arg_load_module,
369                 arg_ro,
370                 arg_blind,
371                 arg_rw,
372                 arg_cdrom,
373                 arg_disk,
374                 arg_debug_messages,
375                 arg_sandbox_server,
376                 arg_sandbox_server_ior,
377                 arg_no_sandbox,
378                 arg_bug_pathname,
379                 arg_syslog,
380                 arg_syslog_facility,
381                 };
382
383
384 /* poptCallbackType captive_popt_callback */
385 static void captive_popt_callback
386                 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data)
387 {
388 gint funci;
389
390         switch (reason) {
391                 case POPT_CALLBACK_REASON_PRE:
392                         arg_syslog_facility_value=-1;
393                         break;
394
395                 case POPT_CALLBACK_REASON_OPTION:
396                         funci=(opt-(captive_popt+POPT_OFFSET));
397                         g_return_if_fail(funci>=0);
398                         g_return_if_fail(funci<(gint)G_N_ELEMENTS(popt_func_table));
399                         if (popt_func_table[funci])
400                                 (*popt_func_table[funci])();
401                         free(captive_popt_optarg);
402                         break;
403
404                 case POPT_CALLBACK_REASON_POST:
405                         if (captive_options->syslog_facility!=-1 && arg_syslog_facility_value!=-1)
406                                 captive_options->syslog_facility=arg_syslog_facility_value;
407
408                         break;
409
410                 default: g_assert_not_reached();
411                 }
412
413         captive_popt_optarg=NULL;       /* sanity */
414 }
415
416
417 gboolean captive_options_parse(struct captive_options *options,const gchar *captive_args)
418 {
419 int errint;
420 int captive_args_argc;
421 const char **captive_args_argv=NULL;
422 poptContext context;
423 gboolean r=FALSE;
424
425         g_return_val_if_fail(options!=NULL,FALSE);
426         g_return_val_if_fail(captive_args!=NULL,FALSE);
427
428         g_assert(captive_options==NULL);
429         captive_options=options;
430
431         errint=poptParseArgvString(captive_args,&captive_args_argc,&captive_args_argv);
432         if (errint!=0) {
433                 g_warning("argument parsing args error: %s",captive_args);
434                 goto args_err;
435                 }
436         context=poptGetContext(
437                         PACKAGE,        /* name */
438                         captive_args_argc,captive_args_argv,    /* argc,argv */
439                         captive_popt_standalone,        /* options */
440                         POPT_CONTEXT_KEEP_FIRST);
441         if (context==NULL) {
442                 g_warning("argument recognization args error: %s",captive_args);
443                 goto args_err_argv;
444                 }
445         errint=poptReadDefaultConfig(context,
446                         TRUE);  /* useEnv */
447         if (errint!=0) {
448                 g_warning("argument recognization args error: %s",captive_args);
449                 goto args_err_context;
450                 }
451         errint=poptGetNextOpt(context);
452         if (errint!=-1) {
453                 g_warning("some non-callbacked argument reached: %s",captive_args);
454                 goto args_err_context;
455                 }
456         if (poptPeekArg(context)) {
457                 g_warning("some non-option argument reached: %s",captive_args);
458                 goto args_err_context;
459                 }
460         r=TRUE; /* success */
461 args_err_context:
462         poptFreeContext(context);
463 args_err_argv:
464         free(captive_args_argv);        /* may be NULL here */
465 args_err:
466         if (!r) {
467                 captive_options=NULL;
468                 return FALSE;
469                 }
470
471         g_assert(captive_options!=NULL);
472         captive_options=NULL;
473
474         return TRUE;
475 }