summaryrefslogtreecommitdiffstats
path: root/private/os2/os2ss/sbcnfg.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/os2/os2ss/sbcnfg.c')
-rw-r--r--private/os2/os2ss/sbcnfg.c1674
1 files changed, 1674 insertions, 0 deletions
diff --git a/private/os2/os2ss/sbcnfg.c b/private/os2/os2ss/sbcnfg.c
new file mode 100644
index 000000000..f93a567d9
--- /dev/null
+++ b/private/os2/os2ss/sbcnfg.c
@@ -0,0 +1,1674 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sbcnfg.c
+
+Abstract:
+
+ This module contains the code necessary to initialize the
+ OS/2 SS entries in the registry. Since the SS modifies the
+ system environment, we need a privileged process to do this,
+ and so we run it in os2ss.exe. This initialization takes
+ place the 1st time that os2ss.exe is run after system setup,
+ or whenever the CONFIG.SYS entry in the registry disappears.
+
+Author:
+
+ Ofer Porat (oferp) 16-Mar-1993
+
+Environment:
+
+ User Mode only
+
+Revision History:
+
+ Code was originally in server\srvcnfg.c.
+
+--*/
+
+//
+// Only compiled for PMNT
+//
+
+#ifdef PMNT
+
+#include <wchar.h>
+#include "os2srv.h"
+
+#define PATHLIST_MAX 1024 // max length of pathlists such as Os2LibPath (in characters)
+#define MAX_CONSYS_SIZE 16384 // max size of config.sys buffers (in bytes)
+#define DOS_DEV_LEN 12 // length of "\\DosDevices\\"
+
+static WCHAR Os2SoftwareDirectory[] = L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft";
+static WCHAR Os2ProductDirectory[] = L"OS/2 Subsystem for NT";
+static WCHAR Os2VersionDirectory[] = L"1.0";
+static WCHAR Os2IniName[] = L"os2.ini";
+static WCHAR Os2ConfigSysName[] = L"config.sys";
+static WCHAR Os2Class[] = L"OS2SS";
+static CHAR Os2ConfigSysDefaultValue[] =
+//
+// The '\a' in the following strings will be replaced by the SystemDirectory Value
+//
+"NTREM Here is a summary of what is allowed to appear in this registry entry:\0"
+"NTREM Comments starting with REM will be visible to the user when s/he opens\0"
+"NTREM c:\\config.sys.\0"
+"NTREM Comments starting with NTREM are only visible by direct access to the\0"
+"NTREM registry.\0"
+"NTREM The following OS/2 configuration commands are significant:\0"
+"NTREM COUNTRY=\0"
+"NTREM CODEPAGE=\0"
+"NTREM DEVINFO=KBD,\0"
+"NTREM Any other commands apart from the exceptions listed below will be\0"
+"NTREM visible to an OS/2 program that opens c:\\config.sys, however they are\0"
+"NTREM not used internally by the NT OS/2 SubSystem.\0"
+"NTREM Exceptions:\0"
+"NTREM The following commands are completely ignored. Their true values\0"
+"NTREM appear in the system environment and should be modified using the\0"
+"NTREM Control Panel System applet. Note that LIBPATH is called Os2LibPath\0"
+"NTREM in the NT system environment.\0"
+"SET PATH=<ignored>\0"
+"LIBPATH=<ignored>\0"
+"NTREM In addition, any \"SET=\" commands (except COMSPEC) will be\0"
+"NTREM completely ignored. You should set OS/2 environment variables just\0"
+"NTREM like any other Windows NT environment variables by using the Control\0"
+"NTREM Panel System applet.\0"
+"NTREM If you have an OS/2 editor available, it is highly recommended that you\0"
+"NTREM modify NT OS/2 config.sys coniguration by editing c:\\config.sys with\0"
+"NTREM this editor. This is the documented way to make such modification, and\0"
+"NTREM is therefore less error-prone.\0"
+"NTREM Now comes the actual text.\0"
+"REM\0"
+"REM This is a fake OS/2 config.sys file used by the NT OS/2 SubSystem.\0"
+"REM The following information resides in the Registry and NOT in a disk file.\0"
+"REM OS/2 Apps that access c:\\config.sys actually manipulate this information.\0"
+"REM\0"
+"PROTSHELL=c:\\os2\\pmshell.exe c:\\os2\\os2.ini c:\\os2\\os2sys.ini \a\\cmd.exe\0"
+"SET COMSPEC=\a\\cmd.exe\0"
+;
+
+static WCHAR Os2ConfigSysKeyName[] =
+L"\\REGISTRY\\MACHINE\\SOFTWARE\\Microsoft\\OS/2 Subsystem for NT\\1.0\\config.sys";
+static WCHAR Os2EnvironmentDirectory[] =
+L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
+static HANDLE Os2EnvironmentKeyHandle = NULL;
+
+static WCHAR Os2OriginalCanonicalConfigSys[] = L"\\DosDevices\\C:\\CONFIG.SYS";
+
+static BOOLEAN Os2LibPathFound = FALSE;
+static WCHAR Os2LibPathValueName[] = L"Os2LibPath";
+static UNICODE_STRING Os2LibPathValueData_U;
+
+static PWSTR pOs2ConfigSys = NULL;
+static ULONG Os2SizeOfConfigSys = 0;
+static PWSTR pOs2UpperCaseConfigSys = NULL;
+
+static WCHAR Os2SystemDirectory[DOS_MAX_PATH_LENGTH];
+
+
+VOID
+Os2InitMBString(
+ PANSI_STRING DestinationString,
+ PCSZ SourceString
+ )
+/*++
+
+Routine Description:
+
+ This routine init an ASCII character string (buffer and length)
+
+Arguments:
+
+ DestinationString - pointer to ansi string to put the result in
+
+ SourceString - pointer to ansi null terminated string to read from
+
+Return Value:
+
+
+Note:
+
+ Od2ProcessCodePage is used as the code page for the mapping.
+
+ Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+--*/
+
+{
+
+ // BUGBUG: add support if Code Page is diff from OEMCP
+
+ RtlInitAnsiString(
+ DestinationString,
+ SourceString);
+
+ return ;
+}
+
+
+NTSTATUS
+Os2MBStringToUnicodeString(
+ PUNICODE_STRING DestinationString,
+ PANSI_STRING SourceString,
+ BOOLEAN AllocateDestinationString
+ )
+/*++
+
+Routine Description:
+
+ This routine map a multibyte character string to its unicode character
+ counterpart.
+
+Arguments:
+
+ DestinationString - pointer to unicode string to get the mapping result
+
+ SourceString - pointer to ansi string to read string to map from
+
+ AllocateDestinationString - flag indicating if need to allocate space
+ for destination string
+
+Return Value:
+
+
+Note:
+
+ Od2ProcessCodePage is used as the code page for the mapping.
+
+ Od2CurrentCodePageIsOem is check to see if RtlOem NLS routines
+ can be used.
+
+--*/
+
+{
+ NTSTATUS Status;
+
+ // BUGBUG: add support if Code Page is diff from OEMCP (use Od2CurrentCodePageIsOem)
+
+ Status = RtlOemStringToUnicodeString(
+ DestinationString,
+ (POEM_STRING)SourceString,
+ AllocateDestinationString
+ );
+
+ return(Status);
+}
+
+
+BOOLEAN
+Os2InitOriginalConfigSysProcessing(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function checks if there is an OS/2 config.sys configuration file on the
+ disk. If so, it opens it and reads it in. The file is converted to UNICODE,
+ and an upper case copy of it is made.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there's an OS/2 config.sys, and all the operations needed to prepare
+ it have succeeded. FALSE otherwise.
+
+Notes:
+ On success Sets global variables as follows:
+ pOs2ConfigSys - a null-terminated UNICODE copy of the OS/2 config.sys.
+ pOs2UpperCaseConfigSys - an upper case copy of pOs2ConfigSys.
+ Os2SizeOfConfigSys - the number of characters in the above strings.
+
+--*/
+
+{
+ UNICODE_STRING CanonicalConfigDotSys_U;
+ UNICODE_STRING Tmp_U;
+ ANSI_STRING Tmp_MB;
+ OBJECT_ATTRIBUTES Obja;
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+ HANDLE ConfigSysFileHandle;
+ PSZ pTempOs2ConfigSys;
+
+ // Try opening OS/2's config.sys file
+
+ RtlInitUnicodeString(&CanonicalConfigDotSys_U, Os2OriginalCanonicalConfigSys);
+
+ InitializeObjectAttributes(&Obja,
+ &CanonicalConfigDotSys_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenFile(&ConfigSysFileHandle,
+ FILE_GENERIC_READ,
+ &Obja,
+ &IoStatus,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtOpenFile-1 %lx\n", Status));
+ }
+#endif
+ return (FALSE);
+ }
+
+ // Get the file length
+
+ Status = NtQueryInformationFile(ConfigSysFileHandle,
+ &IoStatus,
+ &FileStandardInfo,
+ sizeof(FileStandardInfo),
+ FileStandardInformation
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtQueryInformationFile %lx\n", Status));
+ }
+#endif
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ Os2SizeOfConfigSys = FileStandardInfo.EndOfFile.LowPart;
+
+ // Allocate space for reading it in
+
+ // the + 1 in following parameter is for inserting the NUL character
+
+ pTempOs2ConfigSys = (PSZ) RtlAllocateHeap(Os2Heap, 0, Os2SizeOfConfigSys + 1);
+
+ if (pTempOs2ConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pTempOs2ConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ pOs2ConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ if (pOs2ConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2ConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ NtClose(ConfigSysFileHandle);
+ return (FALSE);
+ }
+
+ // Read it in
+
+ Status = NtReadFile(ConfigSysFileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatus,
+ (PVOID)pTempOs2ConfigSys,
+ Os2SizeOfConfigSys,
+ NULL,
+ NULL
+ );
+ NtClose(ConfigSysFileHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - NtReadFile %lx\n", Status));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ pTempOs2ConfigSys[Os2SizeOfConfigSys] = '\0';
+
+ // Convert to UNICODE
+
+ Os2InitMBString(&Tmp_MB, pTempOs2ConfigSys);
+
+ Tmp_U.Buffer = pOs2ConfigSys;
+ Tmp_U.MaximumLength = (USHORT) ((Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+
+ Os2MBStringToUnicodeString(&Tmp_U, &Tmp_MB ,FALSE);
+
+ Os2SizeOfConfigSys = Tmp_U.Length / sizeof(WCHAR);
+
+ pOs2ConfigSys[Os2SizeOfConfigSys] = UNICODE_NULL;
+
+ RtlFreeHeap(Os2Heap, 0, pTempOs2ConfigSys);
+
+ // Prepare the upper case copy
+
+ pOs2UpperCaseConfigSys = (PWSTR) RtlAllocateHeap(Os2Heap, 0, (Os2SizeOfConfigSys + 1) * sizeof(WCHAR));
+ if (pOs2UpperCaseConfigSys == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT )
+ {
+ KdPrint(("Os2InitOriginalConfigSysProcessing): FAILED - RtlAllocateHeap pOs2UpperConfigSys\n"));
+ }
+#endif
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ wcscpy(pOs2UpperCaseConfigSys, pOs2ConfigSys);
+ Or2UnicodeStrupr(pOs2UpperCaseConfigSys);
+
+ //
+ // Verify that the CONFIG.SYS file is really an OS/2 file and not a
+ // DOS file.
+ // Look for certain strings that MUST appear in an OS/2 CONFIG.SYS
+ // file and don't appear in DOS CONFIG.SYS files
+ //
+
+ if ((wcsstr(pOs2UpperCaseConfigSys, L"LIBPATH") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTSHELL") == NULL) ||
+ (wcsstr(pOs2UpperCaseConfigSys, L"PROTECTONLY") == NULL)
+ ) {
+ Os2SizeOfConfigSys = 0;
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+VOID
+Os2SetDirectiveProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process SET directives in OS/2's config.sys
+ file. The directives are entered into the system environment.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UNICODE_STRING VarName_U; // for setting up variable name
+ UNICODE_STRING VarValue_U; // for setting up variable value
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ NTSTATUS Status;
+ ULONG ResultLength;
+ WCHAR wch;
+ KEY_VALUE_PARTIAL_INFORMATION KeyValueInfo;
+
+ // Set up variable name
+
+ VarName_U.Buffer = Value;
+ VarName_U.Length = 0;
+
+ while ((ValueLen > 0) && (*Value != L'=')) {
+ Value++;
+ VarName_U.Length += sizeof(WCHAR);
+ ValueLen--;
+ }
+
+ if (ValueLen == 0 || // End of line reached without finding '='
+ VarName_U.Length == 0) { // Empty name
+ return;
+ }
+
+ VarName_U.MaximumLength = VarName_U.Length;
+
+ // Following SET directives are ignored
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"COMSPEC=", 8) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"PATH=", 5) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIDEO_DEVICES=", 14) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_IBMVGA=", 11) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"VIO_VGA=", 8) ||
+ Or2UnicodeEqualCI(VarName_U.Buffer, L"PROMPT=", 7)
+ ) {
+ return;
+ }
+
+ // Here, we have a valid name, followed by '='
+ Value++; // Skip the '='
+ ValueLen--;
+
+ // Set up variable value
+
+ VarValue_U.Buffer = Value;
+ VarValue_U.Length = (USHORT) (ValueLen * sizeof(WCHAR)); // what's left of the line
+ VarValue_U.MaximumLength = VarValue_U.Length;
+
+ //
+ // Update the information in the registry with the info
+ // in the file
+ //
+
+#if 0
+ // not in effect anymore
+ //
+ // The KEYS variable is handled in a special way.
+ // It's put in the registry config.sys in order to prevent possible
+ // conflict.
+ //
+
+ if (Or2UnicodeEqualCI(VarName_U.Buffer, L"KEYS=", 5)) {
+ RtlMoveMemory(Dest, L"SET ", 8);
+ Dest += 4;
+ RtlMoveMemory(Dest, VarName_U.Buffer, VarName_U.Length);
+ Dest += VarName_U.Length / sizeof(WCHAR);
+ *Dest++ = L'=';
+ RtlMoveMemory(Dest, VarValue_U.Buffer, VarValue_U.Length);
+ Dest += VarValue_U.Length / sizeof(WCHAR);
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+ return;
+ }
+#endif
+
+ //
+ // Otherwise, it's stored in the system environment
+ //
+
+ //
+ // If Os2EnvironmentKeyHandle is NULL, we don't have
+ // write access to the system environment, and we skip
+ // setting the variable.
+ //
+
+ if (Os2EnvironmentKeyHandle == NULL) {
+ return;
+ }
+
+ //
+ // If a value key of the same name already exists,
+ // don't replace it. This is done in order to prevent
+ // the OS/2 SS from overriding possible NT definitions
+ //
+
+ Status = NtQueryValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ KeyValuePartialInformation,
+ &KeyValueInfo,
+ sizeof(KeyValueInfo),
+ &ResultLength
+ );
+
+ if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
+
+ //
+ // Set the system wide variable to the value specified
+ // in the original OS/2 config.sys
+ //
+
+ wch = Value[ValueLen];
+ Value[ValueLen] = UNICODE_NULL;
+
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &VarName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ VarValue_U.Buffer,
+ VarValue_U.Length + sizeof(WCHAR)
+ );
+
+ Value[ValueLen] = wch;
+
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtSetValueKey() system env, rc = %X\n",
+ Status));
+ }
+#endif
+ return;
+ }
+
+ } else {
+#if DBG
+ if (Status != STATUS_BUFFER_OVERFLOW) {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SetDirectiveProcessingDispatchFunction: Unable to NtQueryValueKey() system env, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+ return;
+ }
+}
+
+
+VOID
+Os2CommaProcessingDispatchFunction(
+ IN ULONG DispatchTableIndex,
+ IN PVOID UserParameter,
+ IN PWSTR Name,
+ IN ULONG NameLen,
+ IN PWSTR Value,
+ IN ULONG ValueLen
+ )
+
+/*++
+
+Routine Description:
+
+ This is a Dispatch Routine that is used to process certain directives in OS/2's config.sys
+ file. The directives are copied into the config.sys registry entry we're building.
+ Some directives are truncated after a certain number of commas.
+
+Arguments:
+
+ Standard arguments passed to a Dispatch Function, see the description of
+ Or2IterateEnvironment in ssrtl\consys.c
+
+ UserParameter - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//
+// Lines passed to this dispatch function need to be copied to the output as are
+// except they should be truncated after a certain number of commas. The
+// following table lists the number of commas. 0 means no truncation.
+//
+ ULONG ItemTable[] = { 1, // COUNTRY
+ 0, // CODEPAGE
+ 2 // DEVINFO (only with KBD)
+ };
+ PWSTR Dest = *(PWSTR *) UserParameter;
+ ULONG CommaCtr;
+
+ if (DispatchTableIndex== 2 && !Or2UnicodeEqualCI(Value, L"KBD,", 4)) {
+ return;
+ }
+
+ // First, copy the Name
+
+ RtlMoveMemory(Dest, Name, NameLen * sizeof(WCHAR));
+ Dest += NameLen;
+ *Dest++ = L'=';
+
+ // Now, copy the value for the right number of commas
+
+ CommaCtr = 0;
+
+ while (ValueLen > 0) {
+ if (ItemTable[DispatchTableIndex] != 0 && *Value == L',') {
+ CommaCtr++;
+ if (CommaCtr == ItemTable[DispatchTableIndex]) {
+ break;
+ }
+ }
+
+ *Dest++ = *Value++;
+ ValueLen--;
+ }
+ *Dest++ = UNICODE_NULL;
+ *(PWSTR *) UserParameter = Dest;
+}
+
+
+VOID
+Os2ProcessOriginalConfigSys(
+ IN OUT PWSTR *DestPtr
+ )
+
+/*++
+
+Routine Description:
+
+ This function processes OS/2's config.sys file after it has been properly initialized
+ by Os2InitOriginalConfigSysProcessing.
+
+Arguments:
+
+ DestPtr - points to a pointer which indicates the current position in the
+ config.sys registry entry we're building.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ static ENVIRONMENT_DISPATCH_TABLE_ENTRY DispatchTable[] =
+ {
+ { L"COUNTRY", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"CODEPAGE", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"DEVINFO", L"=", Os2CommaProcessingDispatchFunction, NULL },
+ { L"LIBPATH", L"=", Or2FillInSearchRecordDispatchFunction, NULL },
+ { L"SET", L" \t", Os2SetDirectiveProcessingDispatchFunction, NULL }
+ };
+ ENVIRONMENT_SEARCH_RECORD LibPathRecord;
+ ULONG i;
+ PWSTR p;
+ WCHAR ch;
+
+ //
+ // Most of the job is done by Or2IterateEnvironment which processes the file
+ // according to a dispatch table.
+ //
+ // LibPath needs to be handled a little differently. We need to process only
+ // the *last* occurence of LIBPATH= in the file (this is the same as OS/2).
+ // Therefore we only record the position of the LIBPATH= statments as we run
+ // into them. After we're finished we'll have the position of the last one,
+ // and we can process that line.
+ //
+
+ for (i = 0; i < 5; i++) {
+ DispatchTable[i].UserParameter = (PVOID) DestPtr;
+ }
+
+ DispatchTable[3].UserParameter = (PVOID)&LibPathRecord;
+ LibPathRecord.DispatchTableIndex = (ULONG)-1;
+
+ Or2IterateEnvironment(pOs2ConfigSys,
+ DispatchTable,
+ 5,
+ CRLF_DELIM);
+
+
+ if (Os2LibPathFound && LibPathRecord.DispatchTableIndex != (ULONG)-1) {
+
+ // handle LIBPATH if there was one
+
+ // get a pointer to the upper case version, so we can append it
+
+ p = pOs2UpperCaseConfigSys + (LibPathRecord.Value - pOs2ConfigSys);
+
+ ch = p[LibPathRecord.ValueLen];
+ p[LibPathRecord.ValueLen] = UNICODE_NULL;
+
+ Or2AppendPathToPath(Os2Heap,
+ p,
+ &Os2LibPathValueData_U,
+ TRUE);
+ p[LibPathRecord.ValueLen] = ch;
+ }
+}
+
+
+VOID
+Os2TerminateOriginalConfigSysProcessing(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Cleans up processing of OS/2's config.sys. Releases the storage used to store the
+ file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlFreeHeap(Os2Heap, 0, pOs2ConfigSys);
+ RtlFreeHeap(Os2Heap, 0, pOs2UpperCaseConfigSys);
+ pOs2UpperCaseConfigSys = pOs2ConfigSys = NULL;
+}
+
+
+NTSTATUS
+Os2SbBuildSD(
+ PSECURITY_DESCRIPTOR SecurityDescriptor,
+ PACL *pDacl
+ )
+
+/*++
+
+Routine Description:
+
+ Builds a security descriptor for creating our registry keys.
+
+ Administrators -- all access
+ everyone -- read access
+
+Arguments:
+
+ SecurityDescriptor -- supplies a pointer to a preallocated SD that will be built
+ pDacl -- returns a pointer to a dacl that should be released from Os2Heap after
+ we're finished using the security descriptor.
+
+Return Value:
+
+ NT error code.
+
+--*/
+
+{
+ PACL Dacl;
+ PACE_HEADER Pace;
+ PSID AdminAliasSid;
+ ULONG DaclSize;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY;
+ PSID WorldSid;
+ NTSTATUS Status;
+
+ //
+ // Create the SIDs for local admin and World.
+ //
+
+ Status = RtlAllocateAndInitializeSid(
+ &NtAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(Admin), Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ Status = RtlAllocateAndInitializeSid(
+ &WorldSidAuthority,
+ 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateAndInitializeSid(World), Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ Status = RtlCreateSecurityDescriptor( SecurityDescriptor,
+ SECURITY_DESCRIPTOR_REVISION );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+
+ //
+ // Compute the size of the buffer needed for the
+ // DACL.
+ //
+
+ DaclSize = sizeof( ACL ) +
+ 2 * (sizeof( ACCESS_ALLOWED_ACE ) - sizeof( ULONG ))
+ +
+ RtlLengthSid( AdminAliasSid ) +
+ RtlLengthSid( WorldSid );
+
+ Dacl = (PACL) RtlAllocateHeap(Os2Heap, 0, DaclSize);
+
+ if (Dacl == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAllocateHeap failed\n"));
+ }
+#endif
+ return(STATUS_NO_MEMORY);
+ }
+
+ //
+ // Build the ACL
+ //
+
+ Status = RtlCreateAcl ( Dacl, DaclSize, ACL_REVISION2 );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlCreateAcl, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_ALL,
+ AdminAliasSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlAddAccessAllowedAce (
+ Dacl,
+ ACL_REVISION2,
+ GENERIC_READ,
+ WorldSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlAddAccessAllowedAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Status = RtlGetAce(
+ Dacl,
+ 0L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(Admin), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ Status = RtlGetAce(
+ Dacl,
+ 1L,
+ &Pace
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlGetAce(World), Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ Pace->AceFlags |= CONTAINER_INHERIT_ACE;
+
+ //
+ // Add the ACL to the security descriptor
+ //
+
+ Status = RtlSetDaclSecurityDescriptor(
+ SecurityDescriptor,
+ TRUE,
+ Dacl, // put (PACL) NULL to allow everyone all access
+ FALSE );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbBuildSD: RtlSetDaclSecurityDescriptor, Status = %lx\n", Status));
+ }
+#endif
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ return (Status);
+ }
+
+ //
+ // These have been copied into the security descriptor, so
+ // we can free them.
+ //
+
+ RtlFreeSid( AdminAliasSid );
+
+ RtlFreeSid( WorldSid );
+
+ *pDacl = Dacl;
+
+ return(STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistryKeys(
+ OUT PHANDLE phConfigSysKeyHandle,
+ OUT PHANDLE phEnvironmentKeyHandle
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the OS/2 subsystem key hierarchy in the registry. It also opens
+ the config.sys key, and opens the system environment key.
+
+Arguments:
+
+ phConfigSysKeyHandle - Returns a READ/WRITE handle to the config.sys key in the registry.
+
+ phEnvironmentKeyHandle - Returns a READ/WRITE handle to the system environment key.
+ If this key can't be opened due to access denied, NULL is returned and the
+ return value will be STATUS_SUCCESS.
+
+ Note --- If the return value is not a success return value, none of the above return
+ variables can be considered to be valid.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS().
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES Obja;
+ UNICODE_STRING Class_U;
+ UNICODE_STRING SoftwareDirectory_U;
+ UNICODE_STRING ProductDirectory_U;
+ UNICODE_STRING VersionDirectory_U;
+ UNICODE_STRING Os2IniName_U;
+ UNICODE_STRING ConfigSysName_U;
+ UNICODE_STRING EnvRegDir_U;
+ HANDLE SoftwareKeyHandle;
+ HANDLE ProductKeyHandle;
+ HANDLE VersionKeyHandle;
+ HANDLE Os2IniKeyHandle;
+ HANDLE ConfigSysKeyHandle;
+ HANDLE EnvironmentKeyHandle;
+ ULONG Disposition;
+ NTSTATUS Status;
+ SECURITY_DESCRIPTOR localSecurityDescriptor;
+ PSECURITY_DESCRIPTOR securityDescriptor;
+ PACL Dacl = NULL;
+
+
+ *phConfigSysKeyHandle = NULL;
+ *phEnvironmentKeyHandle = NULL;
+
+ // We start off by creating/opening the registry key hierarchy for our subsystem
+
+ securityDescriptor = &localSecurityDescriptor;
+
+ Status = Os2SbBuildSD(securityDescriptor,
+ &Dacl);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Os2SbBuildSD failed, Status = %lx\n", Status));
+ }
+#endif
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Class_U, Os2Class);
+
+ RtlInitUnicodeString(&SoftwareDirectory_U, Os2SoftwareDirectory);
+ InitializeObjectAttributes(&Obja,
+ &SoftwareDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&SoftwareKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja
+ );
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't open software key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&ProductDirectory_U, Os2ProductDirectory);
+ InitializeObjectAttributes(&Obja,
+ &ProductDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ SoftwareKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ProductKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(SoftwareKeyHandle);
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create product key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&VersionDirectory_U, Os2VersionDirectory);
+ InitializeObjectAttributes(&Obja,
+ &VersionDirectory_U,
+ OBJ_CASE_INSENSITIVE,
+ ProductKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&VersionKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ NtClose(ProductKeyHandle);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create version key, rc = %lx\n", Status));
+ }
+#endif
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+
+ RtlInitUnicodeString(&Os2IniName_U, Os2IniName);
+ InitializeObjectAttributes(&Obja,
+ &Os2IniName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&Os2IniKeyHandle,
+ KEY_CREATE_SUB_KEY,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create os2ini key, rc = %lx\n", Status));
+ }
+#endif
+ NtClose(VersionKeyHandle);
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ return (Status);
+ }
+ NtClose(Os2IniKeyHandle);
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysName_U,
+ OBJ_CASE_INSENSITIVE,
+ VersionKeyHandle,
+ securityDescriptor);
+
+ Status = NtCreateKey(&ConfigSysKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja,
+ 0,
+ &Class_U,
+ REG_OPTION_NON_VOLATILE,
+ &Disposition
+ );
+
+ if (Dacl != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Dacl);
+ }
+ NtClose(VersionKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Can't create/open config.sys key, rc = %lx\n",
+ Status));
+ }
+#endif
+ return(Status);
+ }
+
+ // Open the environment.
+
+ RtlInitUnicodeString(&EnvRegDir_U, Os2EnvironmentDirectory);
+ InitializeObjectAttributes(&Obja,
+ &EnvRegDir_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&EnvironmentKeyHandle,
+ KEY_READ | KEY_WRITE,
+ &Obja
+ );
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistryKeys: Unable to NtOpenKey() the system environment, rc = %lx\n",
+ Status));
+ }
+#endif
+ if (Status != STATUS_ACCESS_DENIED) {
+ NtClose(ConfigSysKeyHandle);
+ return(Status);
+ }
+
+ //
+ // on denied access, return with no error so we can at least create the
+ // config.sys value entry
+ // The caller will know this occured because the environment handle is null.
+ //
+
+ } else {
+ *phEnvironmentKeyHandle = EnvironmentKeyHandle;
+ }
+
+ *phConfigSysKeyHandle = ConfigSysKeyHandle;
+ return (STATUS_SUCCESS);
+}
+
+
+NTSTATUS
+Os2SbInitializeRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function is responsible for initializing the entire Registry component of the
+ Subsystem. It generates the key hierarchy in the registry.
+
+ In the generation of the key hierarchy, it also generates a config.sys entry.
+ The information in this entry is taken from the following sources:
+
+ -- some default strings we put in (see Os2ConfigSysDefaultValue).
+ -- Information from OS/2's config.sys file is added as follows:
+
+ > SET commands are put in the system environment.
+ Some SET commands are ignored (see Os2SetDirectiveProcessingDispatchFunction)
+ > LIBPATH commands are merged to the Os2LibPath variable in the
+ system environment. A terminating semicolon is added if there
+ is only one path in the path list.
+ > SET PATH= is ignored, and the system path remains the same.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value is an NTSTATUS type that is returned when some failure occurs. It may
+ indicate any of several errors that occur during the APIs called in this function.
+ The return value should be tested with NT_SUCCESS(). If an unsuccessful value
+ is returned, it means the registry component was not properly initialized.
+
+--*/
+
+{
+ UNICODE_STRING Os2LibPathValueName_U;
+ HANDLE ConfigSysKeyHandle;
+ NTSTATUS Status;
+ UNICODE_STRING ConfigSysName_U;
+ PWCHAR pInfo;
+ PUCHAR Src;
+ PWCHAR Src1;
+ PWCHAR Dest;
+ WCHAR ch, ch1;
+
+ // Create the key hierarchy
+
+ Status = Os2SbInitializeRegistryKeys(&ConfigSysKeyHandle,
+ &Os2EnvironmentKeyHandle);
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS - Os2SbInitializeRegistry: failed Os2SbInitializeRegistryKeys, rc = %lx\n", Status));
+ }
+#endif
+ return(Status);
+ }
+
+ //
+ // This is the 1st time the subsystem is running, create the config.sys entry
+ // and migrate information from os/2's config.sys file.
+ //
+
+ Os2LibPathFound = FALSE;
+ Os2LibPathValueData_U.Buffer = NULL;
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+ goto Os2NoEnvAccess; // skip over the Os2LibPath stuff
+ }
+
+ // Get Os2LibPath from sys env so we can update it.
+
+ if (!Or2GetEnvPath(&Os2LibPathValueData_U,
+ Os2Heap,
+ PATHLIST_MAX,
+ Os2EnvironmentKeyHandle,
+ Os2LibPathValueName,
+ FALSE)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to fetch Os2LibPath from sys env\n"));
+ }
+#endif
+ } else {
+
+ // make sure there's at lease one semicolon
+
+ Or2CheckSemicolon(&Os2LibPathValueData_U);
+
+ Os2LibPathFound = TRUE;
+ }
+
+ if (Os2LibPathFound && Os2LibPathValueData_U.Length == 0) { // it's empty (or nonexistent)
+ // set up a default
+ UNICODE_STRING tmp;
+
+ RtlInitUnicodeString(&tmp, Os2SystemDirectory);
+
+ RtlCopyUnicodeString(&Os2LibPathValueData_U, &tmp);
+
+ RtlAppendUnicodeToString(&Os2LibPathValueData_U, L"\\os2\\dll;");
+
+ Os2LibPathValueData_U.Buffer[Os2LibPathValueData_U.Length/sizeof(WCHAR)] = UNICODE_NULL;
+ }
+
+Os2NoEnvAccess:
+
+ // Now set up the initial regisry config.sys entry.
+
+ // Allocate a buffer to build the config.sys entry in. (it's a multi-string)
+
+ pInfo = (PWCHAR) RtlAllocateHeap(Os2Heap, 0, MAX_CONSYS_SIZE);
+ if (pInfo == NULL)
+ {
+ if (Os2LibPathValueData_U.Buffer != NULL) {
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ Os2LibPathFound = FALSE;
+ }
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+ NtClose(ConfigSysKeyHandle);
+
+ return (STATUS_BUFFER_TOO_SMALL);
+ }
+
+ // Initially, copy our default value into the entry.
+
+ Src = (PUCHAR) Os2ConfigSysDefaultValue;
+ Dest = pInfo;
+ do
+ {
+ ch = (WCHAR) *Src++;
+ if (ch == L'\a')
+ {
+ Src1 = Os2SystemDirectory;
+ ch1 = *Src1++;
+ while (ch1 != UNICODE_NULL)
+ {
+ *Dest++ = ch1;
+ ch1 = *Src1++;
+ }
+ }
+ else
+ {
+ *Dest++ = ch;
+ }
+ } while (!((ch == UNICODE_NULL) && (*Src == '\0')));
+
+
+ // check if the an OS/2 CONFIG.SYS file already exists on
+ // the drive. Its name will be C:\CONFIG.SYS
+ // If it exists, process it for additional information
+ // The system env will also be updated
+
+ if (Os2InitOriginalConfigSysProcessing()) {
+
+ if (Os2EnvironmentKeyHandle == NULL) { // we have no write access to the environment
+
+ //
+ // We couldn't open a write key to the sys env for some reason, so we
+ // won't be able to migrate SET variables to NT from config.sys.
+ // Perhaps a popup should be generated to notify the user of this at
+ // this point.
+ // Anyway, we go on and only write the config.sys entry, skipping
+ // variable migration.
+ //
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Initializing registry without writing system env\n"));
+ }
+#endif
+ }
+
+ Os2ProcessOriginalConfigSys(&Dest);
+ Os2TerminateOriginalConfigSysProcessing();
+ } else {
+
+ //
+ // add a default "COUNTRY=" line
+ //
+
+ RtlMoveMemory(Dest, L"COUNTRY=", 16);
+ Dest += 8;
+#if 0
+ Dest += swprintf(Dest, L"%.3hu", LANGIDFROMLCID(NtCurrentTeb()->CurrentLocale));
+#else
+ RtlMoveMemory(Dest, L"001", 6);
+ Dest += 3;
+#endif
+ *Dest++ = UNICODE_NULL;
+
+ }
+
+ // Write the new Os2LibPath
+
+ if (Os2LibPathFound) {
+
+ RtlInitUnicodeString(&Os2LibPathValueName_U, Os2LibPathValueName);
+ Status = NtSetValueKey(Os2EnvironmentKeyHandle,
+ &Os2LibPathValueName_U,
+ (ULONG)0,
+ REG_EXPAND_SZ,
+ Os2LibPathValueData_U.Buffer,
+ Os2LibPathValueData_U.Length + sizeof(WCHAR)
+ );
+
+#if DBG
+ if (!NT_SUCCESS(Status))
+ {
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() system environment, rc = %X\n",
+ Status));
+ }
+ }
+#endif
+
+ Os2LibPathFound = FALSE;
+ RtlFreeHeap(Os2Heap, 0, Os2LibPathValueData_U.Buffer);
+ Os2LibPathValueData_U.Buffer = NULL;
+ }
+
+ if (Os2EnvironmentKeyHandle != NULL) {
+ NtClose(Os2EnvironmentKeyHandle);
+ Os2EnvironmentKeyHandle = NULL;
+ }
+
+ // set the REG_MULTI_SZ terminating NUL
+
+ *Dest++ = UNICODE_NULL;
+
+ // Finally, write the config.sys multi-string entry into the registry.
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtSetValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ (ULONG)0,
+ REG_MULTI_SZ,
+ (PVOID)pInfo,
+ (PBYTE)Dest - (PBYTE)pInfo
+ );
+ RtlFreeHeap(Os2Heap, 0, pInfo);
+ if (!NT_SUCCESS(Status))
+ {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("Os2SbInitializeRegistry: Unable to NtSetValueKey() registry config.sys, rc = %X\n",
+ Status));
+ }
+#endif
+ NtClose(ConfigSysKeyHandle);
+ return (Status);
+ }
+
+ NtClose(ConfigSysKeyHandle);
+ return (STATUS_SUCCESS);
+}
+
+
+VOID
+Os2SbProbeForInitialSetup(
+ VOID
+ )
+{
+ OBJECT_ATTRIBUTES Obja;
+ UNICODE_STRING ConfigSysKeyName_U;
+ UNICODE_STRING ConfigSysName_U;
+ PUNICODE_STRING SysDir_U;
+ HANDLE ConfigSysKeyHandle;
+ ULONG ResultLength;
+ USHORT Counter;
+ KEY_VALUE_PARTIAL_INFORMATION ValuePartialInformation;
+ NTSTATUS Status;
+
+#if DBG
+ Os2Debug |= OS2_DEBUG_INIT;
+#endif
+
+ RtlInitUnicodeString(&ConfigSysKeyName_U, Os2ConfigSysKeyName);
+ InitializeObjectAttributes(&Obja,
+ &ConfigSysKeyName_U,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&ConfigSysKeyHandle,
+ KEY_READ,
+ &Obja
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ RtlInitUnicodeString(&ConfigSysName_U, Os2ConfigSysName);
+ Status = NtQueryValueKey(ConfigSysKeyHandle,
+ &ConfigSysName_U,
+ KeyValuePartialInformation,
+ &ValuePartialInformation,
+ 0,
+ &ResultLength
+ );
+
+ NtClose(ConfigSysKeyHandle);
+
+ //
+ // The 2 expected status results are:
+ //
+ // STATUS_OBJECT_NAME_NOT_FOUND - config.sys not yet defined
+ // STATUS_BUFFER_TOO_SMALL - config.sys already defined
+ //
+
+ if (Status == STATUS_BUFFER_TOO_SMALL) {
+ return;
+ }
+
+ if (Status != STATUS_OBJECT_NAME_NOT_FOUND) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Can't Read CONFIG.SYS registry value, Status = %lx\n", Status));
+ }
+#endif
+ return;
+ }
+
+ } else {
+ if (Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_INVALID) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Can't Read CONFIG.SYS registry key, Status = %lx\n", Status));
+ }
+#endif
+ return;
+ }
+ }
+
+
+ //
+ // We need to install the registry stuff
+ //
+
+ //
+ // Create a heap to use for dynamic memory allocation.
+ //
+
+ Os2Heap = RtlCreateHeap( HEAP_GROWABLE,
+ NULL,
+ 0x10000L, // Initial size of heap is 64K
+ 0x1000L, // Commit an initial page
+ NULL,
+ NULL // Reserved
+ );
+ if (Os2Heap == NULL) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Error at RtlCreateHeap of Os2Heap\n"));
+ }
+#endif
+ return;
+ }
+
+ //
+ // Figure out the system directory by cutting it out of our ImagePathName
+ // (should be something like \DosDevices\%SystemRoot%\system32\os2ss.exe)
+ //
+
+ SysDir_U = (PUNICODE_STRING) &NtCurrentPeb()->ProcessParameters->ImagePathName;
+ for (Counter = (SysDir_U->Length / sizeof(WCHAR)) - 1; SysDir_U->Buffer[Counter] != L'\\'; Counter--) {
+ }
+
+ Counter -= DOS_DEV_LEN;
+
+ RtlMoveMemory(Os2SystemDirectory,
+ SysDir_U->Buffer + DOS_DEV_LEN,
+ Counter * sizeof(WCHAR));
+
+ Os2SystemDirectory[Counter] = UNICODE_NULL;
+
+#if 0
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("\nOS2SS: System Directory is "));
+
+ for (Counter = 0; Os2SystemDirectory[Counter] != UNICODE_NULL; Counter++) {
+ KdPrint(("%c", (CHAR) Os2SystemDirectory[Counter]));
+ }
+
+ KdPrint(("|\n"));
+ }
+#endif
+#endif
+
+ Status = Os2SbInitializeRegistry();
+
+ if (!NT_SUCCESS(Status)) {
+#if DBG
+ IF_OS2_DEBUG( INIT ) {
+ KdPrint(("OS2SS: Os2SbInitializeRegistry() failed, Status = %lx\n", Status));
+ }
+#endif
+ }
+
+ RtlDestroyHeap(Os2Heap);
+}
+
+#endif // PMNT