Cosmetic: Removed extraneous 'extern' keyword
[captive.git] / src / libcaptive / client / init.c
1 /* $Id$
2  * Init and cleanup code of libcaptive to be called by client application
3  * Copyright (C) 2002 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/client.h"     /* self */
23 #include "captive/ldr.h"
24 #include "captive/ldr_exports.h"
25 #include "captive/unicode.h"
26 #include "captive/rtl-file.h"
27 #include <glib/gtypes.h>
28 #include <glib/gmessages.h>
29 #include "reactos/internal/ldr.h"
30 #include "reactos/napi/types.h"
31 #include "reactos/internal/kd.h"        /* for KDB_LOADDRIVER_HOOK */
32 #include <fcntl.h>
33 #include <sys/mman.h>   /* for PROT_READ, MAP_SHARED */
34 #include "reactos/ddk/kefuncs.h"        /* for KeInitializeSpinLock() */
35 #include "reactos/internal/ntoskrnl.h"  /* for RtlpInitNlsTables() and IoInit() */
36 #include "reactos/internal/ps.h"        /* for PsInitProcessManagment() and PsInitThreadManagment() */
37 #include "reactos/ddk/iofuncs.h"        /* for IoCreateFile() */
38 #include "captive/storage.h"
39 #include "captive/signal.h"     /* for captive_signal_init() */
40 #include "reactos/ddk/psfuncs.h"        /* for PsGetCurrentThread() */
41 #include <stdio.h>
42 #include "reactos/internal/ex.h"        /* for ExpInitLookasideLists() */
43 #include <popt.h>
44 #include <glib/gstrfuncs.h>
45
46
47 /* Are we initialized? */
48 static gboolean active;
49
50 /* Module of fs module itself loaded by captive_w32_init() */
51 static PMODULE_OBJECT ModuleObject;
52
53 /* Driver in fs module loaded by captive_w32_init() */
54 static DRIVER_OBJECT DriverObject;
55
56 /* Structure holding the pointer to the toplevel IRP */
57 static TOP_LEVEL_IRP TopLevelIrp;       /* TODO:thread */
58
59
60 gchar *captive_option_filesystem;
61 enum captive_option_rwmode captive_option_rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
62 enum captive_option_media captive_option_media=CAPTIVE_OPTION_MEDIA_DISK;
63 GIOChannel *captive_image_iochannel;
64 guint64 captive_image_size;
65
66
67 static gchar *captive_popt_optarg;
68
69
70 static void arg_filesystem(void)
71 {
72         g_free(captive_option_filesystem);
73         captive_option_filesystem=g_strdup(captive_popt_optarg);
74 }
75
76 static void arg_ro(void)
77 {
78         captive_option_rwmode=CAPTIVE_OPTION_RWMODE_RO;
79 }
80 static void arg_blind(void)
81 {
82         captive_option_rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
83 }
84 static void arg_rw(void)
85 {
86         captive_option_rwmode=CAPTIVE_OPTION_RWMODE_RW;
87 }
88
89 static void arg_cdrom(void)
90 {
91         captive_option_media=CAPTIVE_OPTION_MEDIA_CDROM;
92 }
93 static void arg_disk(void)
94 {
95         captive_option_media=CAPTIVE_OPTION_MEDIA_DISK;
96 }
97
98
99 static void captive_popt_callback
100                 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data);
101
102 const struct poptOption captive_popt[]={
103                 { argInfo:POPT_ARG_INTL_DOMAIN, arg:(void *)PACKAGE },
104                 { argInfo:POPT_ARG_CALLBACK,    arg:(void *)captive_popt_callback },
105 #define POPT_OFFSET 2
106 #define CAPTIVE_POPT(longname,argInfoP,argP,descripP,argDescripP) \
107                 { \
108                         longName: (longname), \
109                         shortName: 0, \
110                         argInfo: (argInfoP), \
111                         arg: (void *)argP, \
112                         val: 0, \
113                         descrip: (descripP), \
114                         argDescrip: (argDescripP), \
115                 }
116 #define CAPTIVE_POPT_STRING(longname,descripP,argDescripP) \
117                 CAPTIVE_POPT(longname,POPT_ARG_STRING,&captive_popt_optarg,descripP,argDescripP)
118 #define CAPTIVE_POPT_NONE(longname,descripP) \
119                 CAPTIVE_POPT(longname,POPT_ARG_NONE  ,NULL                ,descripP,NULL       )
120
121                 CAPTIVE_POPT_STRING("filesystem",N_("Path to .sys or .so filesystem module file"),N_("pathname")),
122                 CAPTIVE_POPT_NONE(  "ro"        ,N_("Read/write mode: Any write access will be forbidden")),
123                 CAPTIVE_POPT_NONE(  "blind"     ,N_("Read/write mode: All writes are just simulated in memory (default)")),
124                 CAPTIVE_POPT_NONE(  "rw"        ,N_("Read/write mode: Write directly to the image file/device")),
125                 CAPTIVE_POPT_NONE(  "cdrom"     ,N_("Media type: CD-ROM")),
126                 CAPTIVE_POPT_NONE(  "disk"      ,N_("Media type: Disk (default)")),
127
128 #undef CAPTIVE_POPT_NONE
129 #undef CAPTIVE_POPT_STRING
130 #undef CAPTIVE_POPT
131                 POPT_TABLEEND
132                 };
133
134 static const struct poptOption captive_popt_standalone[]={
135                 CAPTIVE_POPT_INCLUDE,
136                 POPT_AUTOHELP
137                 POPT_TABLEEND
138                 };
139
140
141 static void (*const popt_func_table[])(void)={
142                 arg_filesystem,
143                 arg_ro,
144                 arg_blind,
145                 arg_rw,
146                 arg_cdrom,
147                 arg_disk,
148                 };
149
150
151 /* poptCallbackType captive_popt_callback */
152 static void captive_popt_callback
153                 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data)
154 {
155 gint funci;
156
157         g_return_if_fail(reason==POPT_CALLBACK_REASON_OPTION);
158
159         funci=(opt-(captive_popt+POPT_OFFSET));
160         g_return_if_fail(funci>=0);
161         g_return_if_fail(funci<(gint)G_N_ELEMENTS(popt_func_table));
162         if (popt_func_table[funci])
163                 (*popt_func_table[funci])();
164         free(captive_popt_optarg);
165         captive_popt_optarg=NULL;       /* sanity, shouldn't be needed */
166 }
167
168
169 static gboolean captive_w32_init(void)
170 {
171 NTSTATUS err;
172 gboolean errbool;
173 GIOStatus erriostatus;
174
175         g_return_val_if_fail(captive_option_filesystem!=NULL,FALSE);
176
177         erriostatus=g_io_channel_set_encoding(captive_image_iochannel,
178                         NULL,   /* encoding; force binary data */
179                         NULL);  /* error */
180         g_assert(erriostatus==G_IO_STATUS_NORMAL);
181
182         /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
183         captive_image_size=captive_giochannel_size(captive_image_iochannel);
184         g_return_val_if_fail(captive_image_size>0,FALSE);
185
186         /* Initialize 'FsRtlLegalAnsiCharacterArray'. */
187         captive_FsRtlLegalAnsiCharacterArray_init();
188
189         /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
190         /* ExpInitializeExecutive(); */
191                 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() begins
192                  * here as the rest of the function does a lot of hardware initializations.
193                  */
194                 /* LdrInit1(); */
195                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
196                         InitializeListHead(&ModuleTextListHead);
197                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
198                 KeLowerIrql(DISPATCH_LEVEL);
199                 /*...*/
200                 KeLowerIrql(PASSIVE_LEVEL);
201                 /*...*/
202                 /* create default nls tables */
203                 RtlpInitNlsTables();
204                 /*...*/
205                 ObInit();
206                 /*...*/
207                 /* PiInitProcessManager(); */
208                         /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
209                         PsInitProcessManagment();
210                         PsInitThreadManagment();
211                         /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() ends. */
212                 /*...*/
213                 IoInit();
214                 /* Exinit(); */
215                         /* Part of reactos/ntoskrnl/ex/init.c/Exinit() begins. */
216                         ExpInitLookasideLists();
217                         /* Part of reactos/ntoskrnl/ex/init.c/Exinit() ends. */
218                 /*...*/
219                 /* LdrInitModuleManagement(); */
220                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement() begins
221                          * here as the rest "Create module object for {NTOSKRNL,HAL}"
222                          * is dependent on {NTOSKRNL,HAL} PE image headers not provided by libcaptive.
223                          */
224                         /* Initialize the module list and spinlock */
225                         InitializeListHead(&ModuleListHead);
226                         KeInitializeSpinLock(&ModuleListLock);
227                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
228                 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
229         /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
230
231         /* Simulate our PE headers and export the symbols of {NTOSKRNL,HAL} */
232         captive_kernel_exports();
233
234         errbool=captive_cdrom_init();
235         g_return_val_if_fail(errbool==TRUE,FALSE);
236         errbool=captive_disk_init();
237         g_return_val_if_fail(errbool==TRUE,FALSE);
238
239         err=captive_LdrpLoadAndCallImage(
240                         &ModuleObject,  /* ModuleObjectp */
241                         captive_utf8_to_UnicodeString_alloca(captive_option_filesystem),        /* ModuleName */
242                         &DriverObject,  /* DriverEntry_DriverObject */
243                         captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
244         g_return_val_if_fail(NT_SUCCESS(err),FALSE);
245
246         /* set TopLevelIrp() - FIXME: where is it set by native reactos? */
247         PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
248
249         /* Begin possible handling of foreign W32 binary code here */
250         /* If you want to disable SIGSEGV handler if not needed:
251          *      if (ModuleObject->Flags & MODULE_FLAG_PE)
252          */
253         captive_signal_init();
254
255         return TRUE;
256 }
257
258
259 /**
260  * captive_init:
261  * @captive_args: String with possible options to parse by popt.
262  * %NULL value is permitted.
263  * @image_iochannel: Host OS file of the disk image to mount.
264  * %NULL value is forbidden.
265  *
266  * Initializes %libcaptive and loads the specified filesystem.
267  *
268  * You should supply
269  *
270  * Returns: %TRUE if successfuly loaded.
271  */
272 gboolean captive_init(const gchar *captive_args,GIOChannel *image_iochannel)
273 {
274 gboolean errbool;
275 int errint;
276
277 #ifdef MAINTAINER_MODE
278         g_log_set_always_fatal(~(0
279                         |G_LOG_LEVEL_MESSAGE
280                         |G_LOG_LEVEL_INFO
281                         |G_LOG_LEVEL_DEBUG
282                         ));
283 #endif
284
285         g_return_val_if_fail(active==FALSE,FALSE);
286
287         /* (optionally) parse the given 'captive_args' string */
288         if (captive_args) {
289 int captive_args_argc;
290 const char **captive_args_argv=NULL;
291 poptContext context;
292 gboolean r=FALSE;
293
294                 errint=poptParseArgvString(captive_args,&captive_args_argc,&captive_args_argv);
295                 if (errint!=0) {
296                         g_assert_not_reached(); /* argument parsing args_error */
297                         goto args_err;
298                         }
299                 context=poptGetContext(
300                                 PACKAGE,        /* name */
301                                 captive_args_argc,captive_args_argv,    /* argc,argv */
302                                 captive_popt_standalone,        /* options */
303                                 POPT_CONTEXT_KEEP_FIRST);
304                 if (context==NULL) {
305                         g_assert_not_reached(); /* argument recognization args_error */
306                         goto args_err_argv;
307                         }
308                 errint=poptReadDefaultConfig(context,
309                                 TRUE);  /* useEnv */
310                 if (errint!=0) {
311                         g_assert_not_reached(); /* argument recognization args_error */
312                         goto args_err_context;
313                         }
314                 errint=poptGetNextOpt(context);
315                 if (errint!=-1) {
316                         g_assert_not_reached(); /* some non-callbacked argument reached */
317                         goto args_err_context;
318                         }
319                 /* FIXME: reject non-"--"-prefixed arguments; how to detected them? */
320                 r=TRUE; /* success */
321 args_err_context:
322                 poptFreeContext(context);
323 args_err_argv:
324                 free(captive_args_argv);        /* may be NULL here */
325 args_err:
326                 if (!r) {
327                         puts("FIXME: HELP HERE");
328                         g_return_val_if_reached(r);
329                         }
330                 }
331
332         g_return_val_if_fail(image_iochannel!=NULL,FALSE);
333
334         captive_image_iochannel=image_iochannel;
335         /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
336          * as we yet need to do g_io_channel_set_encoding().
337          */
338
339         errbool=captive_w32_init();
340         g_return_val_if_fail(errbool==TRUE,FALSE);
341
342         active=TRUE;
343         return TRUE;
344 }