2 * Init and cleanup code of libcaptive to be called by client application
3 * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
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
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.
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
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 */
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() */
43 #include <glib/gstrfuncs.h>
44 #include <glib/glist.h>
45 #include <glib/gutils.h> /* for g_atexit() */
46 #include "giochannel-blind.h"
47 #include <glib-object.h>
48 #include "reactos/internal/se.h" /* for SeInit2() */
51 /* Are we initialized? */
52 static gboolean active;
54 /* Module of fs module itself loaded by captive_w32_init() */
55 static PMODULE_OBJECT ModuleObject;
57 /* Driver in fs module loaded by captive_w32_init() */
58 DRIVER_OBJECT captive_DriverObject;
59 PDRIVER_REINITIALIZE captive_DriverObject_ReinitRoutine;
60 PVOID captive_DriverObject_ReinitRoutine_Context;
62 /* Structure holding the pointer to the toplevel IRP */
63 static TOP_LEVEL_IRP TopLevelIrp; /* TODO:thread */
66 gchar *captive_option_filesystem;
67 enum captive_option_rwmode captive_option_rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
68 enum captive_option_media captive_option_media=CAPTIVE_OPTION_MEDIA_DISK;
69 gboolean captive_debug_messages=FALSE;
70 GIOChannel *captive_image_iochannel;
71 /* Non-blinded original GIOChannel for flushing during shutdown. */
72 static GIOChannel *captive_image_iochannel_orig;
73 guint64 captive_image_size;
74 static GList *captive_load_module;
77 static gchar *captive_popt_optarg;
80 static void arg_filesystem(void)
82 g_free(captive_option_filesystem);
83 captive_option_filesystem=g_strdup(captive_popt_optarg);
86 static void arg_load_module(void)
88 captive_load_module=g_list_append(captive_load_module,g_strdup(captive_popt_optarg));
91 static void arg_ro(void)
93 captive_option_rwmode=CAPTIVE_OPTION_RWMODE_RO;
95 static void arg_blind(void)
97 captive_option_rwmode=CAPTIVE_OPTION_RWMODE_BLIND;
99 static void arg_rw(void)
101 captive_option_rwmode=CAPTIVE_OPTION_RWMODE_RW;
104 static void arg_cdrom(void)
106 captive_option_media=CAPTIVE_OPTION_MEDIA_CDROM;
108 static void arg_disk(void)
110 captive_option_media=CAPTIVE_OPTION_MEDIA_DISK;
113 static void arg_debug_messages(void)
115 captive_debug_messages=TRUE;
119 static void captive_popt_callback
120 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data);
122 const struct poptOption captive_popt[]={
123 { argInfo:POPT_ARG_INTL_DOMAIN, arg:(void *)PACKAGE },
124 { argInfo:POPT_ARG_CALLBACK, arg:(void *)captive_popt_callback },
125 #define POPT_OFFSET 2
126 #define CAPTIVE_POPT(longname,argInfoP,argP,descripP,argDescripP) \
128 longName: (longname), \
130 argInfo: (argInfoP), \
133 descrip: (descripP), \
134 argDescrip: (argDescripP), \
136 #define CAPTIVE_POPT_STRING(longname,descripP,argDescripP) \
137 CAPTIVE_POPT(longname,POPT_ARG_STRING,&captive_popt_optarg,descripP,argDescripP)
138 #define CAPTIVE_POPT_NONE(longname,descripP) \
139 CAPTIVE_POPT(longname,POPT_ARG_NONE ,NULL ,descripP,NULL )
141 CAPTIVE_POPT_STRING("filesystem" ,N_("Path to .sys or .so filesystem module file"),N_("pathname")),
142 CAPTIVE_POPT_STRING("load-module" ,N_("Path to any W32 module to load w/o initialization"),N_("pathname")),
143 CAPTIVE_POPT_NONE( "ro" ,N_("Read/write mode: Any write access will be forbidden")),
144 CAPTIVE_POPT_NONE( "blind" ,N_("Read/write mode: All writes are just simulated in memory (default)")),
145 CAPTIVE_POPT_NONE( "rw" ,N_("Read/write mode: Write directly to the image file/device")),
146 CAPTIVE_POPT_NONE( "cdrom" ,N_("Media type: CD-ROM")),
147 CAPTIVE_POPT_NONE( "disk" ,N_("Media type: Disk (default)")),
148 CAPTIVE_POPT_NONE( "debug-messages",N_("Turn on debugging messages")),
150 #undef CAPTIVE_POPT_NONE
151 #undef CAPTIVE_POPT_STRING
156 static const struct poptOption captive_popt_standalone[]={
157 CAPTIVE_POPT_INCLUDE,
163 static void (*const popt_func_table[])(void)={
175 /* poptCallbackType captive_popt_callback */
176 static void captive_popt_callback
177 (poptContext con,enum poptCallbackReason reason,const struct poptOption *opt,const char *arg,const void *data)
181 g_return_if_fail(reason==POPT_CALLBACK_REASON_OPTION);
183 funci=(opt-(captive_popt+POPT_OFFSET));
184 g_return_if_fail(funci>=0);
185 g_return_if_fail(funci<(gint)G_N_ELEMENTS(popt_func_table));
186 if (popt_func_table[funci])
187 (*popt_func_table[funci])();
188 free(captive_popt_optarg);
189 captive_popt_optarg=NULL; /* sanity, shouldn't be needed */
193 static gboolean captive_w32_init(void)
197 GIOStatus erriostatus;
199 g_return_val_if_fail(captive_option_filesystem!=NULL,FALSE);
201 erriostatus=g_io_channel_set_encoding(captive_image_iochannel,
202 NULL, /* encoding; force binary data */
204 g_assert(erriostatus==G_IO_STATUS_NORMAL);
206 /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
207 captive_image_size=captive_giochannel_size(captive_image_iochannel);
208 g_return_val_if_fail(captive_image_size>0,FALSE);
210 /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
211 /* ExpInitializeExecutive(); */
212 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() begins
213 * here as the rest of the function does a lot of hardware initializations.
216 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
217 InitializeListHead(&ModuleTextListHead);
218 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
219 KeLowerIrql(DISPATCH_LEVEL);
221 /* create default nls tables */
226 KeInitializeDispatcher();
228 KeLowerIrql(PASSIVE_LEVEL);
230 g_assert(errbool==TRUE);
233 g_assert(errbool==TRUE);
234 /* PiInitProcessManager(); */
235 /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
236 PsInitProcessManagment();
237 PsInitThreadManagment();
238 /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() ends. */
242 /* LdrInitModuleManagement(); */
243 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement() begins
244 * here as the rest "Create module object for {NTOSKRNL,HAL}"
245 * is dependent on {NTOSKRNL,HAL} PE image headers not provided by libcaptive.
247 /* Initialize the module list and spinlock */
248 InitializeListHead(&ModuleListHead);
249 KeInitializeSpinLock(&ModuleListLock);
250 /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
253 NtInitializeEventImplementation();
255 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
256 /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
258 /* Simulate our PE headers and export the symbols of our complete libraries */
259 captive_kernel_exports();
261 errbool=captive_cdrom_init();
262 g_return_val_if_fail(errbool==TRUE,FALSE);
263 errbool=captive_disk_init();
264 g_return_val_if_fail(errbool==TRUE,FALSE);
266 while (captive_load_module) {
267 gchar *modulename=captive_load_module->data;
268 PMODULE_OBJECT ModuleObject_tmp;
271 /* load the module */
273 captive_utf8_to_UnicodeString_alloca(modulename), /* ModuleName */
274 &ModuleObject_tmp); /* ModuleObjectp */
275 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
277 captive_load_module=g_list_remove(captive_load_module,modulename);
280 /* Patch 'ntoskrnl.exe' loaded by 'captive_load_module' above. */
281 captive_kernel_patches();
283 /* Initialize 'FsRtlLegalAnsiCharacterArray'.
284 * It requires 'ntoskrnl.exe' loaded by 'captive_load_module' above;
285 * captive_kernel_patches() should not be needed.
287 captive_FsRtlLegalAnsiCharacterArray_init();
289 /* set TopLevelIrp() - FIXME: where is it set by native reactos? */
290 PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
292 /* Begin possible handling of foreign W32 binary code here */
293 /* If you want to disable SIGSEGV handler if not needed:
294 * if (ModuleObject->Flags & MODULE_FLAG_PE)
296 captive_signal_init();
298 /* You must have already captive_signal_init() passed here as the module may
299 * call some functions from W32 ntoskrnl.exe.
301 captive_DriverObject_ReinitRoutine=NULL;
302 err=captive_LdrpLoadAndCallImage(
303 &ModuleObject, /* ModuleObjectp */
304 captive_utf8_to_UnicodeString_alloca(captive_option_filesystem), /* ModuleName */
305 &captive_DriverObject, /* DriverEntry_DriverObject */
306 captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
307 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
308 if (captive_DriverObject_ReinitRoutine) {
309 (*captive_DriverObject_ReinitRoutine)(
310 &captive_DriverObject, /* DriverObject */
311 captive_DriverObject_ReinitRoutine_Context, /* Context */
312 1); /* Count: # of calls of ReinitRoutine incl. the current one */
319 static void captive_shutdown_atexit(void);
322 static void log_discard_func(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
330 * @captive_args: String with possible options to parse by popt.
331 * %NULL value is permitted.
332 * @image_iochannel: Host OS file of the disk image to mount.
333 * %NULL value is permitted (initialization would not apply in such case).
335 * Initializes %libcaptive and loads the specified filesystem.
336 * You can supply %NULL value for @image_iochannel - in such case no library
337 * initialization is done; only passed @captive_args are parsed. Function
338 * will return you %FALSE value as it is not yet initializied.
340 * You should supply only @captive_args with %NULL @image_iochannel if you
341 * need to parse+examine the arguments to properly initialize @image_iochannel.
343 * Returns: %TRUE if successfuly initialized.
345 gboolean captive_init(const gchar *captive_args,GIOChannel *image_iochannel)
350 #ifdef MAINTAINER_MODE
351 g_log_set_always_fatal(~(0
358 g_return_val_if_fail(active==FALSE,FALSE);
360 /* Initialize GObject subsystem of GLib. */
363 /* (optionally) parse the given 'captive_args' string */
365 int captive_args_argc;
366 const char **captive_args_argv=NULL;
370 errint=poptParseArgvString(captive_args,&captive_args_argc,&captive_args_argv);
372 g_assert_not_reached(); /* argument parsing args_error */
375 context=poptGetContext(
377 captive_args_argc,captive_args_argv, /* argc,argv */
378 captive_popt_standalone, /* options */
379 POPT_CONTEXT_KEEP_FIRST);
381 g_assert_not_reached(); /* argument recognization args_error */
384 errint=poptReadDefaultConfig(context,
387 g_assert_not_reached(); /* argument recognization args_error */
388 goto args_err_context;
390 errint=poptGetNextOpt(context);
392 g_assert_not_reached(); /* some non-callbacked argument reached */
393 goto args_err_context;
395 if (poptPeekArg(context)) {
396 g_assert_not_reached(); /* some non-"--"-prefixed argument reached */
397 goto args_err_context;
399 r=TRUE; /* success */
401 poptFreeContext(context);
403 free(captive_args_argv); /* may be NULL here */
406 puts("FIXME: HELP HERE");
407 g_return_val_if_reached(r);
411 /* If we were just requested to parse the arguments. */
412 if (!image_iochannel)
415 if (!captive_debug_messages) {
417 G_LOG_DOMAIN, /* log_domain; "Captive" */
419 | G_LOG_FLAG_RECURSION
421 | G_LOG_LEVEL_MESSAGE
424 log_discard_func, /* log_func */
425 NULL); /* user_data */
428 if (captive_option_rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
429 captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(image_iochannel);
431 captive_image_iochannel=image_iochannel;
432 captive_image_iochannel_orig=image_iochannel;
434 /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
435 * as we yet need to do g_io_channel_set_encoding().
438 errbool=captive_w32_init();
439 g_return_val_if_fail(errbool==TRUE,FALSE);
441 g_atexit(captive_shutdown_atexit);
451 * Closes down %libcaptive. It should flush all pending buffers and successfuly
452 * close the filesystem. Variable #captive_image_iochannel will be set to %NULL,
453 * you should close such channel yourself.
455 * Returns: %TRUE if successfuly shutdown.
457 gboolean captive_shutdown(void)
459 GIOStatus erriostatus;
461 g_return_val_if_fail(active==TRUE,FALSE);
462 g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
464 captive_PoQueueShutdownWorkItem_hooklist_invoke();
466 /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
467 * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
469 IoShutdownRegisteredFileSystems();
470 IoShutdownRegisteredDevices();
472 /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
473 erriostatus=g_io_channel_flush(
474 captive_image_iochannel, /* channel */
476 g_assert(erriostatus==G_IO_STATUS_NORMAL);
478 /* 'captive_image_iochannel' may be blinded wrapper. */
479 if (captive_image_iochannel!=captive_image_iochannel_orig) {
480 erriostatus=g_io_channel_flush(
481 captive_image_iochannel_orig, /* channel */
483 g_assert(erriostatus==G_IO_STATUS_NORMAL);
486 captive_image_iochannel=NULL;
493 static void captive_shutdown_atexit(void)