Author: hbelusca Date: Sat May 2 01:23:27 2015 New Revision: 67505
URL: http://svn.reactos.org/svn/reactos?rev=67505&view=rev Log: [NTVDM] - Fix command-line handling. - Disable a hack introduced in r65012 for testing purposes.
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dem.c [iso-8859-1] Sat May 2 01:23:27 2015 @@ -116,29 +116,33 @@ { case 0x08: // Launch external command { -#define CMDLINE_LENGTH 1024 - BOOL Result; DWORD dwExitCode;
LPSTR Command = (LPSTR)SEG_OFF_TO_PTR(getDS(), getSI()); - LPSTR CmdPtr = Command; - CHAR CommandLine[CMDLINE_LENGTH] = ""; + CHAR CmdLine[sizeof("cmd.exe /c ") + DOS_CMDLINE_LENGTH + 1] = ""; + LPSTR CmdLinePtr; + ULONG CmdLineLen; STARTUPINFOA StartupInfo; PROCESS_INFORMATION ProcessInformation;
- /* NULL-terminate the command line by removing the return carriage character */ - while (*CmdPtr && *CmdPtr != '\r') CmdPtr++; - *CmdPtr = '\0'; - - DPRINT1("CMD Run Command '%s'\n", Command); - /* Spawn a user-defined 32-bit command preprocessor */
- /* Build the command line */ // FIXME: Use COMSPEC env var!! - strcpy(CommandLine, "cmd.exe /c "); - strcat(CommandLine, Command); + CmdLinePtr = CmdLine; + strcpy(CmdLinePtr, "cmd.exe /c "); + CmdLinePtr += strlen(CmdLinePtr); + + /* Build a Win32-compatible command-line */ + CmdLineLen = min(strlen(Command), sizeof(CmdLine) - strlen(CmdLinePtr) - 1); + RtlCopyMemory(CmdLinePtr, Command, CmdLineLen); + CmdLinePtr[CmdLineLen] = '\0'; + + /* Remove any trailing return carriage character and NULL-terminate the command line */ + while (*CmdLinePtr && *CmdLinePtr != '\r' && *CmdLinePtr != '\n') CmdLinePtr++; + *CmdLinePtr = '\0'; + + DPRINT1("CMD Run Command '%s' ('%s')\n", Command, CmdLine);
RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); RtlZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); @@ -148,7 +152,7 @@ VidBiosDetachFromConsole();
Result = CreateProcessA(NULL, - CommandLine, + CmdLine, NULL, NULL, TRUE, @@ -159,7 +163,7 @@ &ProcessInformation); if (Result) { - DPRINT1("Command '%s' launched successfully\n", Command); + DPRINT1("Command '%s' ('%s') launched successfully\n", Command, CmdLine);
/* Wait for process termination */ WaitForSingleObject(ProcessInformation.hProcess, INFINITE); @@ -173,7 +177,7 @@ } else { - DPRINT1("Failed when launched command '%s'\n"); + DPRINT1("Failed when launched command '%s' ('%s')\n", Command, CmdLine); dwExitCode = GetLastError(); }
@@ -210,7 +214,7 @@ PVOID Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize);
UNREFERENCED_PARAMETER(Parameter); - ASSERT(Env != NULL); + ASSERT(Env);
do { @@ -253,7 +257,11 @@ }
/* Start the process from the command line */ - DPRINT1("Starting '%s' ('%s')...\n", AppName, CmdLine); + DPRINT1("Starting '%s' ('%.*s')...\n", + AppName, + CommandInfo.CmdLen >= 2 ? CommandInfo.CmdLen - 2 /* Display the command line without the terminating 0d 0a */ + : CommandInfo.CmdLen + CmdLine); Result = DosStartProcess(AppName, CmdLine, Env); if (Result != ERROR_SUCCESS) { @@ -467,8 +475,7 @@
/* Start the process from the command line */ DPRINT1("Starting '%s' ('%s')...\n", ApplicationName, CommandLine); - Result = DosStartProcess(ApplicationName, - CommandLine, + Result = DosStartProcess(ApplicationName, CommandLine, SEG_OFF_TO_PTR(SYSTEM_ENV_BLOCK, 0)); if (Result != ERROR_SUCCESS) {
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/dos.c [iso-8859-1] Sat May 2 01:23:27 2015 @@ -160,59 +160,6 @@ }
/* PUBLIC FUNCTIONS ***********************************************************/ - -VOID DosInitializePsp(WORD PspSegment, - LPCSTR CommandLine, - WORD ProgramSize, - WORD Environment, - DWORD ReturnAddress) -{ - PDOS_PSP PspBlock = SEGMENT_TO_PSP(PspSegment); - LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress); - - RtlZeroMemory(PspBlock, sizeof(*PspBlock)); - - /* Set the exit interrupt */ - PspBlock->Exit[0] = 0xCD; // int 0x20 - PspBlock->Exit[1] = 0x20; - - /* Set the number of the last paragraph */ - PspBlock->LastParagraph = PspSegment + ProgramSize - 1; - - /* Save the interrupt vectors */ - PspBlock->TerminateAddress = ReturnAddress; - PspBlock->BreakAddress = IntVecTable[0x23]; - PspBlock->CriticalAddress = IntVecTable[0x24]; - - /* Set the parent PSP */ - PspBlock->ParentPsp = CurrentPsp; - - /* Copy the parent handle table */ - DosCopyHandleTable(PspBlock->HandleTable); - - /* Set the environment block */ - PspBlock->EnvBlock = Environment; - - /* Set the handle table pointers to the internal handle table */ - PspBlock->HandleTableSize = 20; - PspBlock->HandleTablePtr = MAKELONG(0x18, PspSegment); - - /* Set the DOS version */ - PspBlock->DosVersion = DOS_VERSION; - - /* Set the far call opcodes */ - PspBlock->FarCall[0] = 0xCD; // int 0x21 - PspBlock->FarCall[1] = 0x21; - PspBlock->FarCall[2] = 0xCB; // retf - - if (CommandLine) - { - /* Set the command line */ - PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH - 1); - RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize); - PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r'; - } -}
VOID WINAPI DosInt20h(LPWORD Stack) { @@ -1388,30 +1335,45 @@ /* Execute */ case 0x4B: { - DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)getAL(); + BYTE OrgAL = getAL(); LPSTR ProgramName = SEG_OFF_TO_PTR(getDS(), getDX()); PDOS_EXEC_PARAM_BLOCK ParamBlock = SEG_OFF_TO_PTR(getES(), getBX()); DWORD ReturnAddress = MAKELONG(Stack[STACK_IP], Stack[STACK_CS]); WORD ErrorCode; - + + if (OrgAL <= DOS_LOAD_OVERLAY) + { + DOS_EXEC_TYPE LoadType = (DOS_EXEC_TYPE)OrgAL; + #ifndef STANDALONE - if (LoadType == DOS_LOAD_AND_EXECUTE) - { - /* Create a new process */ - ErrorCode = DosCreateProcess(ProgramName, ParamBlock, ReturnAddress); - } - else - { -#else - { + if (LoadType == DOS_LOAD_AND_EXECUTE) + { + /* Create a new process */ + ErrorCode = DosCreateProcess(ProgramName, + ParamBlock, + ReturnAddress); + } + else #endif - /* Just load an executable */ - ErrorCode = DosLoadExecutable(LoadType, - ProgramName, - ParamBlock, - NULL, - NULL, - ReturnAddress); + { + /* Just load an executable */ + ErrorCode = DosLoadExecutable(LoadType, + ProgramName, + ParamBlock, + NULL, + NULL, + ReturnAddress); + } + } + else if (OrgAL == 0x05) + { + // http://www.ctyme.com/intr/rb-2942.htm + DPRINT1("Set execution state is UNIMPLEMENTED\n"); + ErrorCode = ERROR_CALL_NOT_IMPLEMENTED; + } + else + { + ErrorCode = ERROR_INVALID_FUNCTION; }
if (ErrorCode == ERROR_SUCCESS)
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/d... ============================================================================== --- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] (original) +++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] Sat May 2 01:23:27 2015 @@ -37,10 +37,13 @@ { PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment);
- /* Set the command line */ - PspBlock->CommandLineSize = (BYTE)min(strlen(CommandLine), DOS_CMDLINE_LENGTH - 1); - RtlCopyMemory(PspBlock->CommandLine, CommandLine, PspBlock->CommandLineSize); - PspBlock->CommandLine[PspBlock->CommandLineSize] = '\r'; + /* + * Copy the command line block. + * Format of the CommandLine parameter: 1 byte for size; 127 bytes for contents. + */ + PspBlock->CommandLineSize = min(*(PBYTE)CommandLine, DOS_CMDLINE_LENGTH); + CommandLine++; + RtlCopyMemory(PspBlock->CommandLine, CommandLine, DOS_CMDLINE_LENGTH); }
static WORD DosCopyEnvironmentBlock(LPCSTR Environment OPTIONAL, @@ -115,8 +118,8 @@
VOID DosClonePsp(WORD DestSegment, WORD SourceSegment) { - PDOS_PSP DestPsp = SEGMENT_TO_PSP(DestSegment); - PDOS_PSP SourcePsp = SEGMENT_TO_PSP(SourceSegment); + PDOS_PSP DestPsp = SEGMENT_TO_PSP(DestSegment); + PDOS_PSP SourcePsp = SEGMENT_TO_PSP(SourceSegment); LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
/* Literally copy the PSP first */ @@ -132,7 +135,7 @@
/* Set the handle table pointers to the internal handle table */ DestPsp->HandleTableSize = DEFAULT_JFT_SIZE; - DestPsp->HandleTablePtr = MAKELONG(0x18, DestSegment); + DestPsp->HandleTablePtr = MAKELONG(0x18, DestSegment);
/* Copy the parent handle table without referencing the SFT */ RtlCopyMemory(FAR_POINTER(DestPsp->HandleTablePtr), @@ -142,7 +145,7 @@
VOID DosCreatePsp(WORD Segment, WORD ProgramSize) { - PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment); + PDOS_PSP PspBlock = SEGMENT_TO_PSP(Segment); LPDWORD IntVecTable = (LPDWORD)((ULONG_PTR)BaseAddress);
RtlZeroMemory(PspBlock, sizeof(*PspBlock)); @@ -170,7 +173,7 @@
/* Set the handle table pointers to the internal handle table */ PspBlock->HandleTableSize = DEFAULT_JFT_SIZE; - PspBlock->HandleTablePtr = MAKELONG(0x18, Segment); + PspBlock->HandleTablePtr = MAKELONG(0x18, Segment);
/* Set the DOS version */ PspBlock->DosVersion = DOS_VERSION; @@ -203,6 +206,9 @@ WORD MaxAllocSize; DWORD i, FileSize;
+ /* Buffer for command line conversion: 1 byte for size; 127 bytes for contents */ + CHAR CmdLineBuffer[1 + DOS_CMDLINE_LENGTH]; + DPRINT1("DosLoadExecutable(%d, %s, 0x%08X, 0x%08X)\n", LoadType, ExecutablePath, @@ -249,24 +255,72 @@
if (LoadType != DOS_LOAD_OVERLAY) { - LPSTR CmdLinePtr; - - if (CommandLine == NULL) - { - /* Get the command line from the parameter block */ + /* If an optional Win32 command line is given... */ + if (CommandLine) + { + /* ... convert it into DOS format */ + BYTE CmdLineLen; + + PBYTE CmdLineSize = (PBYTE)CmdLineBuffer; + LPSTR CmdLineStart = CmdLineBuffer + 1; + LPSTR CmdLinePtr = CmdLineStart; + + // For debugging purposes + RtlFillMemory(CmdLineBuffer, sizeof(CmdLineBuffer), 0xFF); + + /* + * Set the command line: it is either an empty command line or has + * the format: " foo bar ..." (with at least one leading whitespace), + * and is then always followed by '\r' (and optionally by '\n'). + */ + CmdLineLen = (BYTE)strlen(CommandLine); + *CmdLineSize = 0; + + /* + * Add the leading space if the command line is not empty + * and doesn't already start with some whitespace... + */ + if (*CommandLine && *CommandLine != '\r' && *CommandLine != '\n' && + *CommandLine != ' ' && *CommandLine != '\t') + { + (*CmdLineSize)++; + *CmdLinePtr++ = ' '; + } + + /* Compute the number of characters we need to copy from the original command line */ + CmdLineLen = min(CmdLineLen, DOS_CMDLINE_LENGTH - *CmdLineSize); + + /* The trailing '\r' or '\n' do not count in the PSP command line size parameter */ + while (CmdLineLen && (CommandLine[CmdLineLen - 1] == '\r' || CommandLine[CmdLineLen - 1] == '\n')) + { + CmdLineLen--; + } + + /* Finally, set everything up */ + *CmdLineSize += CmdLineLen; + RtlCopyMemory(CmdLinePtr, CommandLine, CmdLineLen); + CmdLineStart[*CmdLineSize] = '\r'; + + /* Finally make the pointer point to the static buffer */ + CommandLine = CmdLineBuffer; + } + else + { + /* + * ... otherwise, get the one from the parameter block. + * Format of the command line: 1 byte for size; 127 bytes for contents. + */ + ASSERT(Parameters); CommandLine = (LPCSTR)FAR_POINTER(Parameters->CommandLine); }
+ /* If no optional environment is given... */ if (Environment == NULL) { - /* Get the environment from the parameter block */ + /* ... get the one from the parameter block */ + ASSERT(Parameters); Environment = (LPCSTR)SEG_OFF_TO_PTR(Parameters->Environment, 0); } - - /* NULL-terminate the command line by removing the return carriage character */ - CmdLinePtr = (LPSTR)CommandLine; - while (*CmdLinePtr && *CmdLinePtr != '\r') CmdLinePtr++; - *CmdLinePtr = '\0';
/* Copy the environment block to DOS memory */ EnvBlock = DosCopyEnvironmentBlock(Environment, ExecutablePath); @@ -352,6 +406,7 @@ } else { + ASSERT(Parameters); LoadSegment = Parameters->Overlay.Segment; RelocFactor = Parameters->Overlay.RelocationFactor; } @@ -391,8 +446,9 @@ } else if (LoadType == DOS_LOAD_ONLY) { + ASSERT(Parameters); Parameters->StackLocation = MAKELONG(Header->e_sp, LoadSegment + Header->e_ss); - Parameters->EntryPoint = MAKELONG(Header->e_ip, LoadSegment + Header->e_cs); + Parameters->EntryPoint = MAKELONG(Header->e_ip, LoadSegment + Header->e_cs); } } else @@ -436,9 +492,11 @@ } else { + ASSERT(Parameters); LoadSegment = Parameters->Overlay.Segment; }
+ /* Copy the program to the code segment */ RtlCopyMemory(SEG_OFF_TO_PTR(LoadSegment, 0), Address, FileSize); @@ -465,8 +523,9 @@ } else if (LoadType == DOS_LOAD_ONLY) { + ASSERT(Parameters); Parameters->StackLocation = MAKELONG(0xFFFE, Segment); - Parameters->EntryPoint = MAKELONG(0x0100, Segment); + Parameters->EntryPoint = MAKELONG(0x0100, Segment); } }
@@ -513,8 +572,9 @@ // HACK: Simulate a ENTER key release scancode on the PS/2 port because // some apps expect to read a key release scancode (> 0x80) when they // are started. - IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port - IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release + // (hbelusca 2 May 2015: I'm not sure it's really useful. See r65012) + // IOWriteB(PS2_CONTROL_PORT, 0xD2); // Next write is for the first PS/2 port + // IOWriteB(PS2_DATA_PORT, 0x80 | 0x1C); // ENTER key release
/* Start simulation */ SetEvent(VdmTaskEvent); @@ -537,18 +597,24 @@ DWORD BinaryType; LPVOID Environment = NULL; VDM_COMMAND_INFO CommandInfo; - CHAR CmdLine[MAX_PATH]; + CHAR CmdLine[MAX_PATH]; // DOS_CMDLINE_LENGTH + 1 CHAR AppName[MAX_PATH]; CHAR PifFile[MAX_PATH]; CHAR Desktop[MAX_PATH]; CHAR Title[MAX_PATH]; + LPSTR CmdLinePtr; + ULONG CmdLineSize; ULONG EnvSize = 256; - PVOID Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize); + PVOID Env; STARTUPINFOA StartupInfo; PROCESS_INFORMATION ProcessInfo;
/* Get the binary type */ if (!GetBinaryTypeA(ProgramName, &BinaryType)) return GetLastError(); + + /* Initialize Win32-VDM environment */ + Env = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, EnvSize); + if (Env == NULL) return GetLastError();
/* Did the caller specify an environment segment? */ if (Parameters->Environment) @@ -561,9 +627,25 @@ RtlZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo);
+ /* + * Convert the DOS command line to Win32-compatible format. + * Format of the DOS command line: 1 byte for size; 127 bytes for contents. + */ + CmdLineSize = min(*(PBYTE)FAR_POINTER(Parameters->CommandLine), DOS_CMDLINE_LENGTH); + RtlCopyMemory(CmdLine, + FAR_POINTER(Parameters->CommandLine) + 1, + CmdLineSize); + /* NULL-terminate it */ + CmdLine[CmdLineSize] = '\0'; + + /* Remove any trailing return carriage character and NULL-terminate the command line */ + CmdLinePtr = CmdLine; + while (*CmdLinePtr && *CmdLinePtr != '\r' && *CmdLinePtr != '\n') CmdLinePtr++; + *CmdLinePtr = '\0'; + /* Create the process */ if (!CreateProcessA(ProgramName, - FAR_POINTER(Parameters->CommandLine), + CmdLine, NULL, NULL, FALSE, @@ -573,6 +655,7 @@ &StartupInfo, &ProcessInfo)) { + RtlFreeHeap(RtlGetProcessHeap(), 0, Env); return GetLastError(); }