GLib messages are always fatal sandbox child as we have the right to fail.
[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/ldr.h"
23 #include "captive/ldr_exports.h"
24 #include "captive/unicode.h"
25 #include "captive/rtl-file.h"
26 #include <glib/gtypes.h>
27 #include <glib/gmessages.h>
28 #include "reactos/internal/ldr.h"
29 #include "reactos/napi/types.h"
30 #include "reactos/internal/kd.h"        /* for KDB_LOADDRIVER_HOOK */
31 #include <fcntl.h>
32 #include <sys/mman.h>   /* for PROT_READ, MAP_SHARED */
33 #include "reactos/ddk/kefuncs.h"        /* for KeInitializeSpinLock() */
34 #include "reactos/internal/ntoskrnl.h"  /* for RtlpInitNlsTables() and IoInit() */
35 #include "reactos/internal/ps.h"        /* for PsInitProcessManagment() and PsInitThreadManagment() */
36 #include "reactos/ddk/iofuncs.h"        /* for IoCreateFile() */
37 #include "captive/storage.h"
38 #include "captive/signal.h"     /* for captive_signal_init() */
39 #include "reactos/ddk/psfuncs.h"        /* for PsGetCurrentThread() */
40 #include <stdio.h>
41 #include <popt.h>
42 #include <glib/gstrfuncs.h>
43 #include <glib/glist.h>
44 #include "giochannel-blind.h"
45 #include <glib-object.h>
46 #include "reactos/internal/se.h"        /* for SeInit2() */
47 #include "captive/leave.h"
48 #include "captive/options.h"
49
50
51 struct captive_options *captive_options;
52
53 /* Are we initialized? */
54 static gboolean active;
55
56 /* Module of fs module itself loaded by captive_w32_init() */
57 static PMODULE_OBJECT ModuleObject;
58
59 /* Driver in fs module loaded by captive_w32_init() */
60 DRIVER_OBJECT captive_DriverObject;
61 PDRIVER_REINITIALIZE captive_DriverObject_ReinitRoutine;
62 PVOID captive_DriverObject_ReinitRoutine_Context;
63
64 /* Structure holding the pointer to the toplevel IRP */
65 static TOP_LEVEL_IRP TopLevelIrp;       /* TODO:thread */
66
67
68 void *_local_unwind2_addr;
69
70
71 /* Acceleration hack for ntoskrnl/dbg/print.c/DbgPrint() */
72 gboolean captive_get_debug_messages(void)
73 {
74         g_return_val_if_fail(captive_options!=NULL,TRUE);
75
76         return captive_options->debug_messages;
77 }
78
79
80 static gboolean captive_w32_init(void)
81 {
82 NTSTATUS err;
83 gboolean errbool;
84 GIOStatus erriostatus;
85
86         g_return_val_if_fail(captive_options!=NULL,FALSE);
87         g_return_val_if_fail(captive_options->filesystem.type!=CAPTIVE_OPTIONS_MODULE_TYPE_EMPTY,FALSE);
88
89         erriostatus=g_io_channel_set_encoding(captive_image_iochannel,
90                         NULL,   /* encoding; force binary data */
91                         NULL);  /* error */
92         g_assert(erriostatus==G_IO_STATUS_NORMAL);
93
94         /* captive_giochannel_size() only _after_ g_io_channel_set_encoding() ! */
95         captive_image_size=captive_giochannel_size(captive_image_iochannel);
96         g_return_val_if_fail(captive_image_size>0,FALSE);
97
98         /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() begins. */
99         /* ExpInitializeExecutive(); */
100                 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() begins
101                  * here as the rest of the function does a lot of hardware initializations.
102                  */
103                 /* LdrInit1(); */
104                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() begins. */
105                         InitializeListHead(&ModuleTextListHead);
106                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInit1() ends. */
107                 KeLowerIrql(DISPATCH_LEVEL);
108                 /*...*/
109                 /* create default nls tables */
110                 RtlpInitNlsTables();
111                 /*...*/
112                 /* KeInit2() */
113                         /*...*/
114                         KeInitializeDispatcher();
115                         /*...*/
116                 KeLowerIrql(PASSIVE_LEVEL);
117                 errbool=SeInit1();
118                 g_assert(errbool==TRUE);
119                 ObInit();
120                 errbool=SeInit2();
121                 g_assert(errbool==TRUE);
122                 /* PiInitProcessManager(); */
123                         /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() begins. */
124                         PsInitProcessManagment();
125                         PsInitThreadManagment();
126                         /* Part of reactos/ntoskrnl/ps/psmgr.c/PiInitProcessManager() ends. */
127                 /*...*/
128                 IoInit();
129                 /*...*/
130                 /* LdrInitModuleManagement(); */
131                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement() begins
132                          * here as the rest "Create module object for {NTOSKRNL,HAL}"
133                          * is dependent on {NTOSKRNL,HAL} PE image headers not provided by libcaptive.
134                          */
135                         /* Initialize the module list and spinlock */
136                         InitializeListHead(&ModuleListHead);
137                         KeInitializeSpinLock(&ModuleListLock);
138                         /* Part of reactos/ntoskrnl/ldr/loader.c/LdrInitModuleManagement ends. */
139                 /*...*/
140                 /* Ntinit(); */
141                         NtInitializeEventImplementation();
142                         /*...*/
143                 /* Part of reactos/ntoskrnl/ke/main.c/ExpInitializeExecutive() ends. */
144         /* Part of reactos/ntoskrnl/ke/main.c/KiSystemStartup() ends. */
145
146         /* Simulate our PE headers and export the symbols of our complete libraries */
147         captive_kernel_exports();
148
149         errbool=captive_cdrom_init();
150         g_return_val_if_fail(errbool==TRUE,FALSE);
151         errbool=captive_disk_init();
152         g_return_val_if_fail(errbool==TRUE,FALSE);
153
154         while (captive_options->load_module) {
155 PMODULE_OBJECT ModuleObject_tmp;
156 NTSTATUS err;
157
158                 /* load the module */
159                 err=captive_LdrLoadModule(
160                                 captive_options->load_module->data,
161                                 &ModuleObject_tmp);     /* ModuleObjectp */
162                 g_return_val_if_fail(NT_SUCCESS(err),FALSE);
163
164                 captive_options_module_free(captive_options->load_module->data);
165                 /* also frees 'options->load_module->data' */
166                 captive_options->load_module=g_list_delete_link(captive_options->load_module,captive_options->load_module);
167                 }
168
169         /* Patch 'ntoskrnl.exe' loaded by 'captive_options->load_module' above. */
170         {
171         CHAR *KeNumberProcessorsp=captive_Module_GetExportAddress("ntoskrnl.exe","KeNumberProcessors");
172         
173                 g_assert(*KeNumberProcessorsp==0);
174                 *KeNumberProcessorsp=KeNumberProcessors;
175                 g_assert(*KeNumberProcessorsp==1);
176                 }
177         /* Apply captive_kernel_patches() AFTER any symbols sanity checks above! */
178         captive_kernel_patches();
179
180         _local_unwind2_addr=captive_Module_GetExportAddress("ntoskrnl.exe","_local_unwind2");
181
182         /* Initialize 'FsRtlLegalAnsiCharacterArray'.
183          * It requires 'ntoskrnl.exe' loaded by 'captive_options->load_module' above;
184          * captive_kernel_patches() should not be needed.
185          */
186         captive_FsRtlLegalAnsiCharacterArray_init();
187
188         /* set TopLevelIrp() - FIXME: where is it set by native reactos? */
189         PsGetCurrentThread()->TopLevelIrp=&TopLevelIrp; /* otherwise Io{Get,Set}TopLevelIrp() would SIGSEGV */
190
191         /* Begin possible handling of foreign W32 binary code here */
192         /* If you want to disable SIGSEGV handler if not needed:
193          *      if (ModuleObject->Flags & MODULE_FLAG_PE)
194          */
195         captive_signal_init();
196
197         /* You must have already captive_signal_init() passed here as the module may
198          * call some functions from W32 ntoskrnl.exe.
199          */
200         captive_DriverObject_ReinitRoutine=NULL;
201         err=captive_LdrpLoadAndCallImage(
202                         &ModuleObject,  /* ModuleObjectp */
203                         &captive_options->filesystem,   /* options_module */
204                         &captive_DriverObject,  /* DriverEntry_DriverObject */
205                         captive_utf8_to_UnicodeString_alloca("\\captive\\filesystem")); /* DriverEntry_RegistryPath */
206         g_return_val_if_fail(NT_SUCCESS(err),FALSE);
207         if (captive_DriverObject_ReinitRoutine) {
208                 (*captive_DriverObject_ReinitRoutine)(
209                                 &captive_DriverObject,  /* DriverObject */
210                                 captive_DriverObject_ReinitRoutine_Context,     /* Context */
211                                 1);     /* Count: # of calls of ReinitRoutine incl. the current one */
212                 }
213
214         return TRUE;
215 }
216
217
218 static void     log_discard_func(const gchar *log_domain,GLogLevelFlags log_level,const gchar *message,gpointer user_data)
219 {
220         /* NOP */
221 }
222
223
224 /**
225  * captive_init:
226  *
227  * Expects #captive_options: Parsed by captive_options_parse().
228  * %NULL value is forbidden. Field #image_iochannel %NULL value is forbidden.
229  *
230  * Initializes %libcaptive and loads the specified filesystem.
231  *
232  * Returns: %TRUE if successfuly initialized.
233  */
234 gboolean captive_init(void)
235 {
236 gboolean errbool;
237
238         /* We are in sandbox child and we have the right to fail. */
239         g_log_set_always_fatal(~(0
240                         |G_LOG_LEVEL_MESSAGE
241                         |G_LOG_LEVEL_INFO
242                         |G_LOG_LEVEL_DEBUG
243                         ));
244
245         g_return_val_if_fail(active==FALSE,FALSE);
246
247         g_return_val_if_fail(captive_options!=NULL,FALSE);
248         g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
249
250         /* Initialize GObject subsystem of GLib. */
251         g_type_init();
252
253         if (!captive_options->debug_messages) {
254                 g_log_set_handler(
255                                 G_LOG_DOMAIN,   /* log_domain; "Captive" */
256                                 0       /* log_levels */
257                                                 | G_LOG_FLAG_RECURSION
258                                                 | G_LOG_FLAG_FATAL
259                                                 /* The same mask is in:
260                                                  * libcaptive/sandbox/server-GLogFunc.c
261                                                  * libcaptive/client/init.c
262                                                  * libcaptive/client/vfs.c
263                                                  */
264                                                 | G_LOG_LEVEL_MESSAGE
265                                                 | G_LOG_LEVEL_INFO
266                                                 | G_LOG_LEVEL_DEBUG,
267                                 log_discard_func,       /* log_func */
268                                 NULL);  /* user_data */
269                 }
270
271         if (captive_options->rwmode==CAPTIVE_OPTION_RWMODE_BLIND)
272                 captive_image_iochannel=(GIOChannel *)captive_giochannel_blind_new(captive_options->image_iochannel);
273         else
274                 captive_image_iochannel=captive_options->image_iochannel;
275
276         /* Do not initialize 'captive_image_size' by captive_giochannel_size() here
277          * as we yet need to do g_io_channel_set_encoding().
278          */
279
280         errbool=captive_w32_init();
281         g_return_val_if_fail(errbool==TRUE,FALSE);
282
283         active=TRUE;
284         return TRUE;
285 }
286
287
288 BOOLEAN captive_cc_FileObject_delete(FILE_OBJECT *FileObject);
289 void captive_cc_flush(void);
290
291 /**
292  * captive_shutdown:
293  *
294  * Closes down %libcaptive. It should flush all pending buffers and successfuly
295  * close the filesystem. Variable #captive_options->image_iochannel will not be set to %NULL,
296  * you should close such channel yourself.
297  *
298  * Returns: %TRUE if successfuly shutdown.
299  */
300 gboolean captive_shutdown(void)
301 {
302 GIOStatus erriostatus;
303
304         g_return_val_if_fail(active==TRUE,FALSE);
305         g_return_val_if_fail(captive_image_iochannel!=NULL,FALSE);
306         g_return_val_if_fail(captive_options->image_iochannel!=NULL,FALSE);
307
308         /* Invoke all pending idle functions just to not to forget for anything... */
309         while (g_main_context_iteration(
310                         NULL,   /* context; NULL means default one */
311                         FALSE)) /* may_block */
312                 g_log(G_LOG_DOMAIN,G_LOG_LEVEL_DEBUG,"%s: g_main_context_iteration() proceeded",G_STRLOC);
313
314         captive_PoQueueShutdownWorkItem_hooklist_invoke();
315         captive_cc_flush();
316
317         /* During IoShutdownRegisteredFileSystems() - IRP_MJ_SHUTDOWN to be specific
318          * some buffers will be written but after the IofCallDriver() it will be
319          * no longer possible to flush such buffers to their DeviceVolumeFile.
320          * Therefore we must flush such buffers on the fly although such behaviour
321          * would crash us in regular case as filesystems access BCBs even after their
322          * CcUnpinData().
323          */
324         captive_cc_unmounting=TRUE;
325
326         /* FIXME: ntoskrnl/ex/power.c/NtShutdownSystem() does
327          * IoShutdownRegistered{Devices,FileSystems} order; is it correct?
328          */
329         IoShutdownRegisteredFileSystems();
330
331         /* Just a sanity check as all the dirty data should
332          * get already flushed during IoShutdownRegisteredFileSystems().
333          */
334         captive_cc_FileObject_delete(
335                         NULL);  /* FileObject */
336
337         IoShutdownRegisteredDevices();
338
339         /* libcaptive is not authorized to shutdown 'captive_image_channel'. */
340         erriostatus=g_io_channel_flush(
341                         captive_image_iochannel,        /* channel */
342                         NULL);  /* error */
343         g_assert(erriostatus==G_IO_STATUS_NORMAL);
344
345         /* 'captive_image_iochannel' may be blinded wrapper of 'captive_options->image_iochannel'. */
346         if (captive_image_iochannel!=captive_options->image_iochannel) {
347                 erriostatus=g_io_channel_flush(
348                                 captive_options->image_iochannel,       /* channel */
349                                 NULL);  /* error */
350                 g_assert(erriostatus==G_IO_STATUS_NORMAL);
351                 g_io_channel_unref(captive_image_iochannel);
352                 }
353
354         captive_image_iochannel=NULL;
355
356         active=FALSE;
357         return TRUE;
358 }