CSR Reloaded... well, split.
[reactos.git] / reactos / subsys / csr / csrsrv / init.c
1 /* $Id$
2 *
3 * subsys/csr/csrsrv/init.c - CSR server - initialization
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 * --------------------------------------------------------------------
25 */
26
27 #include "srv.h"
28
29 //#define NDEBUG
30 #include <debug.h>
31
32
33 typedef enum {
34 CSRAT_UNKNOWN=0,
35 CSRAT_OBJECT_DIRECTORY,
36 CSRAT_SUBSYSTEM_TYPE,
37 CSRAT_REQUEST_THREADS, /* ReactOS extension */
38 CSRAT_REQUEST_THREADS_MAX,
39 CSRAT_PROFILE_CONTROL,
40 CSRAT_SHARED_SECTION,
41 CSRAT_SERVER_DLL,
42 CSRAT_WINDOWS,
43 CSRAT_SESSIONS, /* ReactOS extension */
44 CSRAT_MAX
45 } CSR_ARGUMENT_TYPE, *PCSR_ARGUMENT_TYPE;
46
47 typedef struct _CSR_ARGUMENT_ITEM
48 {
49 CSR_ARGUMENT_TYPE Type;
50 UNICODE_STRING Data;
51 union {
52 UNICODE_STRING ObjectDirectory;
53 CSR_SUBSYSTEM_TYPE SubSystemType;
54 USHORT RequestThreads;
55 USHORT MaxRequestThreads;
56 BOOL ProfileControl;
57 BOOL Windows;
58 BOOL Sessions;
59 CSR_SERVER_DLL ServerDll;
60 struct {
61 USHORT PortSectionSize; // 1024k; 128k..?
62 USHORT InteractiveDesktopHeapSize; // 3072k; 128k..
63 USHORT NonInteractiveDesktopHeapSize; // (InteractiveDesktopHeapSize); 128k..
64 USHORT Reserved; /* unused */
65 } SharedSection;
66 } Item;
67
68 } CSR_ARGUMENT_ITEM, * PCSR_ARGUMENT_ITEM;
69
70 /**********************************************************************
71 * CsrpStringToBool/3 PRIVATE
72 */
73 static BOOL STDCALL CsrpStringToBool (LPWSTR TestString, LPWSTR TrueString, LPWSTR FalseString)
74 {
75 if((0 == wcscmp(TestString, TrueString)))
76 {
77 return TRUE;
78 }
79 if((0 == wcscmp(TestString, FalseString)))
80 {
81 return FALSE;
82 }
83 DPRINT1("CSRSRV:%s: replacing invalid value '%S' with '%S'!\n",
84 __FUNCTION__, TestString, FalseString);
85 return FALSE;
86 }
87 /**********************************************************************
88 * CsrpSplitServerDll/2 PRIVATE
89 *
90 * RETURN VALUE
91 * 0: syntax error
92 * 2: ServerDll=="basesrv,1"
93 * 3: ServerDll=="winsrv:UserServerDllInitialization,3"
94 */
95 static INT STDCALL CsrpSplitServerDll (LPWSTR ServerDll, PCSR_ARGUMENT_ITEM pItem)
96 {
97 LPWSTR DllName = NULL;
98 LPWSTR DllEntryPoint = NULL;
99 LPWSTR DllId = NULL;
100 static LPWSTR DefaultDllEntryPoint = L"ServerDllInitialization";
101 LPWSTR tmp = NULL;
102 INT rc = 0;
103 PCSR_SERVER_DLL pCsrServerDll = & pItem->Item.ServerDll;
104
105 if (L'\0' == *ServerDll)
106 {
107 return 0;
108 }
109 /*
110 * DllName (required)
111 */
112 DllName = ServerDll;
113 if (NULL == DllName)
114 {
115 return 0;
116 }
117 /*
118 * DllEntryPoint (optional)
119 */
120 DllEntryPoint = wcschr (ServerDll, L':');
121 if (NULL == DllEntryPoint)
122 {
123 DllEntryPoint = DefaultDllEntryPoint;
124 tmp = ServerDll;
125 rc = 2;
126 } else {
127 tmp = ++DllEntryPoint;
128 rc = 3;
129 }
130 /*
131 * DllId (required)
132 */
133 DllId = wcschr (tmp, L',');
134 if (NULL == DllId)
135 {
136 return 0;
137 }
138 *DllId++ = L'\0';
139 // OK
140 pCsrServerDll->ServerIndex = wcstoul (DllId, NULL, 10);
141 pCsrServerDll->Unused = 0;
142 RtlInitUnicodeString (& pCsrServerDll->DllName, DllName);
143 RtlInitUnicodeString (& pCsrServerDll->DllEntryPoint, DllEntryPoint);
144 return rc;
145 }
146 /**********************************************************************
147 * CsrpSplitSharedSection/2 PRIVATE
148 *
149 * RETURN VALUE
150 * 0: syntax error
151 * 1: PortSectionSize (required)
152 * 2: PortSection,InteractiveDesktopHeap
153 * 3: PortSection,InteractiveDesktopHeap,NonInteractiveDesktopHeap
154 */
155 static INT STDCALL CsrpSplitSharedSection (LPWSTR SharedSection, PCSR_ARGUMENT_ITEM pItem)
156 {
157 LPWSTR PortSectionSize = NULL;
158 LPWSTR InteractiveDesktopHeapSize = NULL;
159 LPWSTR NonInteractiveDesktopHeapSize = NULL;
160 INT rc = 1;
161
162 DPRINT("CSRSRV:%s(%S) called\n", __FUNCTION__, SharedSection);
163
164 if(L'\0' == *SharedSection)
165 {
166 DPRINT("CSRSRV:%s(%S): *SharedSection == L'\\0'\n", __FUNCTION__, SharedSection);
167 return 0;
168 }
169
170 // PortSectionSize (required)
171 PortSectionSize = SharedSection;
172 // InteractiveDesktopHeapSize (optional)
173 InteractiveDesktopHeapSize = wcschr (PortSectionSize, L',');
174 if (NULL == InteractiveDesktopHeapSize)
175 {
176 // Default value is 128k
177 InteractiveDesktopHeapSize = L"128";
178 } else {
179 rc = 2;
180 }
181 // NonInteractiveDesktopHeapSize (optional)
182 NonInteractiveDesktopHeapSize = wcschr (InteractiveDesktopHeapSize, L',');
183 if (NULL == NonInteractiveDesktopHeapSize)
184 {
185 // Default value equals interactive one
186 NonInteractiveDesktopHeapSize = InteractiveDesktopHeapSize;
187 } else {
188 rc = 3;
189 }
190 // OK - normalization
191 pItem->Item.SharedSection.PortSectionSize = wcstoul (PortSectionSize, NULL, 10);
192 if (pItem->Item.SharedSection.PortSectionSize < 64)
193 {
194 pItem->Item.SharedSection.PortSectionSize = 64;
195 }
196 pItem->Item.SharedSection.InteractiveDesktopHeapSize = wcstoul (InteractiveDesktopHeapSize, NULL, 10);
197 if (pItem->Item.SharedSection.InteractiveDesktopHeapSize < 128)
198 {
199 pItem->Item.SharedSection.InteractiveDesktopHeapSize = 128;
200 }
201 pItem->Item.SharedSection.NonInteractiveDesktopHeapSize = wcstoul (NonInteractiveDesktopHeapSize, NULL, 10);
202 if (pItem->Item.SharedSection.NonInteractiveDesktopHeapSize < 128)
203 {
204 pItem->Item.SharedSection.NonInteractiveDesktopHeapSize = 128;
205 }
206 // done
207 return rc;
208 }
209 /**********************************************************************
210 * CsrpParseArgumentItem/1 PRIVATE
211 *
212 * DESCRIPTION
213 *
214 * ARGUMENTS
215 * Argument: argument to decode;
216 *
217 * RETURN VALUE
218 * STATUS_SUCCESS; otherwise, STATUS_UNSUCCESSFUL and
219 * pItem->Type = CSRAT_UNKNOWN.
220 *
221 * NOTE
222 * The command line could be as complex as the following one,
223 * which is the original command line for the Win32 subsystem
224 * in NT 5.1:
225 *
226 * %SystemRoot%\system32\csrss.exe
227 * ObjectDirectory=\Windows
228 * SharedSection=1024,3072,512
229 * Windows=On
230 * SubSystemType=Windows
231 * ServerDll=basesrv,1
232 * ServerDll=winsrv:UserServerDllInitialization,3
233 * ServerDll=winsrv:ConServerDllInitialization,2
234 * ProfileControl=Off
235 * MaxRequestThreads=16
236 */
237 static NTSTATUS FASTCALL CsrpParseArgumentItem (IN OUT PCSR_ARGUMENT_ITEM pItem)
238 {
239 NTSTATUS Status = STATUS_SUCCESS;
240 LPWSTR ParameterName = NULL;
241 LPWSTR ParameterValue = NULL;
242
243 pItem->Type = CSRAT_UNKNOWN;
244
245 if(0 == pItem->Data.Length)
246 {
247 DPRINT1("CSRSRV:%s: (0 == Data.Length)!\n", __FUNCTION__);
248 return STATUS_INVALID_PARAMETER;
249 }
250 //--- Seek '=' to split name and value
251 ParameterName = pItem->Data.Buffer;
252 ParameterValue = wcschr (ParameterName, L'=');
253 if (NULL == ParameterValue)
254 {
255 DPRINT1("CSRSRV:%s: (NULL == ParameterValue)!\n", __FUNCTION__);
256 return STATUS_INVALID_PARAMETER;
257 }
258 *ParameterValue++ = L'\0';
259 DPRINT("Name=%S, Value=%S\n", ParameterName, ParameterValue);
260 //---
261 if(0 == wcscmp(ParameterName, L"ObjectDirectory"))
262 {
263 RtlInitUnicodeString (& pItem->Item.ObjectDirectory, ParameterValue);
264 pItem->Type = CSRAT_OBJECT_DIRECTORY;
265 }
266 else if(0 == wcscmp(ParameterName, L"SubSystemType"))
267 {
268 pItem->Type = CSRAT_SUBSYSTEM_TYPE;
269 pItem->Item.Windows = CsrpStringToBool (ParameterValue, L"Windows", L"Text");
270 }
271 else if(0 == wcscmp(ParameterName, L"MaxRequestThreads"))
272 {
273 pItem->Item.MaxRequestThreads = (USHORT) wcstoul (ParameterValue, NULL, 10);
274 pItem->Type = CSRAT_REQUEST_THREADS_MAX;
275 }
276 else if(0 == wcscmp(ParameterName, L"RequestThreads"))
277 {
278 // ROS Extension
279 pItem->Item.RequestThreads = (USHORT) wcstoul (ParameterValue, NULL, 10);
280 pItem->Type = CSRAT_REQUEST_THREADS;
281 }
282 else if(0 == wcscmp(ParameterName, L"ProfileControl"))
283 {
284 pItem->Item.ProfileControl = CsrpStringToBool (ParameterValue, L"On", L"Off");
285 pItem->Type = CSRAT_PROFILE_CONTROL;
286 }
287 else if(0 == wcscmp(ParameterName, L"SharedSection"))
288 {
289 if (0 != CsrpSplitSharedSection(ParameterValue, pItem))
290 {
291 pItem->Type = CSRAT_SHARED_SECTION;
292 } else {
293 pItem->Type = CSRAT_UNKNOWN;
294 return STATUS_INVALID_PARAMETER;
295 }
296 }
297 else if(0 == wcscmp(ParameterName, L"ServerDll"))
298 {
299 if (0 != CsrpSplitServerDll(ParameterValue, pItem))
300 {
301 pItem->Type = CSRAT_SERVER_DLL;
302 } else {
303 pItem->Type = CSRAT_UNKNOWN;
304 return STATUS_INVALID_PARAMETER;
305 }
306 }
307 else if(0 == wcscmp(ParameterName, L"Windows"))
308 {
309 pItem->Item.Windows = CsrpStringToBool (ParameterValue, L"On", L"Off");
310 pItem->Type = CSRAT_WINDOWS;
311 }
312 else if(0 == wcscmp(ParameterName, L"Sessions"))
313 {
314 // ROS Extension
315 pItem->Item.Sessions = CsrpStringToBool (ParameterValue, L"On", L"Off");
316 pItem->Type = CSRAT_SESSIONS;
317 }
318 else
319 {
320 DPRINT1("CSRSRV:%s: unknown parameter '%S'!\n", __FUNCTION__, ParameterName);
321 pItem->Type = CSRAT_UNKNOWN;
322 Status = STATUS_INVALID_PARAMETER;
323 }
324 return Status;
325 }
326 /**********************************************************************
327 * CsrServerInitialization/2
328 *
329 * DESCRIPTION
330 * Every environment subsystem implicitly starts where this
331 * routines stops. This routine is called by CSR on startup
332 * and then it calls the entry points in the following server
333 * DLLs, as per command line.
334 *
335 * ARGUMENTS
336 * ArgumentCount:
337 * Argument:
338 *
339 * RETURN VALUE
340 * STATUS_SUCCESS if it succeeds. Otherwise a status code.
341 *
342 * NOTE
343 * This is the only function explicitly called by csr.exe.
344 */
345 NTSTATUS STDCALL CsrServerInitialization (ULONG ArgumentCount,
346 LPWSTR *Argument)
347 {
348 NTSTATUS Status = STATUS_SUCCESS;
349 ULONG ArgumentIndex = 0;
350 CSR_ARGUMENT_ITEM ArgumentItem = {CSRAT_UNKNOWN,};
351
352 // get registry bootstrap options
353 for (ArgumentIndex = 0; ArgumentIndex < ArgumentCount; ArgumentIndex++)
354 {
355 RtlInitUnicodeString (& ArgumentItem.Data, Argument[ArgumentIndex]);
356 Status = CsrpParseArgumentItem (& ArgumentItem);
357 if (NT_SUCCESS(Status))
358 {
359 switch (ArgumentItem.Type)
360 {
361 case CSRAT_UNKNOWN:
362 // ignore unknown parameters
363 DPRINT1("CSRSRV: ignoring param '%s'\n", Argument[ArgumentIndex]);
364 break;
365 case CSRAT_OBJECT_DIRECTORY:
366 RtlDuplicateUnicodeString (1, & ArgumentItem.Item.ObjectDirectory, & CsrSrvOption.NameSpace.Root);
367 DPRINT("ObjectDirectory: '%S'\n", CsrSrvOption.NameSpace.Root.Buffer);
368 break;
369 case CSRAT_SUBSYSTEM_TYPE:
370 CsrSrvOption.SubSystemType = ArgumentItem.Item.SubSystemType;
371 DPRINT("SubSystemType: %u\n", CsrSrvOption.SubSystemType);
372 break;
373 case CSRAT_REQUEST_THREADS:
374 CsrSrvOption.Threads.RequestCount = ArgumentItem.Item.RequestThreads;
375 DPRINT("RequestThreads: %u\n", CsrSrvOption.Threads.RequestCount);
376 break;
377 case CSRAT_REQUEST_THREADS_MAX:
378 CsrSrvOption.Threads.MaxRequestCount = ArgumentItem.Item.MaxRequestThreads;
379 DPRINT("MaxRequestThreads: %u\n", CsrSrvOption.Threads.MaxRequestCount);
380 break;
381 case CSRAT_PROFILE_CONTROL:
382 CsrSrvOption.Flag.ProfileControl = ArgumentItem.Item.ProfileControl;
383 DPRINT("ProfileControl: %u \n", CsrSrvOption.Flag.ProfileControl);
384 break;
385 case CSRAT_SHARED_SECTION:
386 CsrSrvOption.PortSharedSectionSize = ArgumentItem.Item.SharedSection.PortSectionSize;
387 CsrSrvOption.Heap.InteractiveDesktopHeapSize = ArgumentItem.Item.SharedSection.InteractiveDesktopHeapSize;
388 CsrSrvOption.Heap.NonInteractiveDesktopHeapSize = ArgumentItem.Item.SharedSection.NonInteractiveDesktopHeapSize;
389 DPRINT("SharedSection: %u-%u-%u\n",
390 CsrSrvOption.PortSharedSectionSize,
391 CsrSrvOption.Heap.InteractiveDesktopHeapSize,
392 CsrSrvOption.Heap.NonInteractiveDesktopHeapSize);
393 break;
394 case CSRAT_SERVER_DLL:
395 Status = CsrSrvRegisterServerDll (& ArgumentItem.Item.ServerDll);
396 if(!NT_SUCCESS(Status))
397 {
398 DPRINT1("CSRSRV: CsrSrvRegisterServerDll(%S) failed!\n",
399 Argument[ArgumentIndex]);
400 } else {
401 DPRINT("ServerDll: DLL='%S' Entrypoint='%S' ID=%u\n",
402 ArgumentItem.Item.ServerDll.DllName.Buffer,
403 ArgumentItem.Item.ServerDll.DllEntryPoint.Buffer,
404 ArgumentItem.Item.ServerDll.ServerIndex);
405 }
406 break;
407 case CSRAT_WINDOWS:
408 CsrSrvOption.Flag.Windows = ArgumentItem.Item.Windows;
409 DPRINT("Windows: %d\n", CsrSrvOption.Flag.Windows);
410 break;
411 case CSRAT_SESSIONS:
412 CsrSrvOption.Flag.Sessions = ArgumentItem.Item.Sessions;
413 DPRINT("Sessions: %d\n", CsrSrvOption.Flag.Sessions);
414 break;
415 default:
416 DPRINT("CSRSRV: unknown ArgumentItem->Type=%ld!\n", ArgumentItem.Type);
417 }
418 } else {
419 DPRINT1("CSRSRV:%s: CsrpParseArgumentItem(%S) failed with Status = %08lx\n",
420 __FUNCTION__, Argument[ArgumentIndex], Status);
421 }
422 }
423 // TODO: verify required
424 Status = CsrSrvBootstrap ();
425 return Status;
426 }
427 /* EOF */