mirror of
https://github.com/reactos/reactos.git
synced 2024-08-20 18:35:32 +00:00
650 lines
18 KiB
C
650 lines
18 KiB
C
/* $Id$
|
|
*
|
|
* PROJECT : ReactOS Operating System / POSIX+ Environment Subsystem
|
|
* DESCRIPTION: POSIXW32 - A DEC VT-100 terminal emulator for the PSX subsystem
|
|
* DESCRIPTION: that runs in the Win32 subsystem.
|
|
* COPYRIGHT : Copyright (c) 2001-2002 Emanuele Aliberti
|
|
* LICENSE : GNU GPL v2
|
|
* DATE : 2001-05-05
|
|
* AUTHOR : Emanuele Aliberti <ea@iol.it>
|
|
* NOTE : This IS a Win32 program, but will fail if the PSX subsystem
|
|
* NOTE : is not installed. The PSX subsystem consists of two more
|
|
* NOTE : files: PSXSS.EXE, PSXDLL.DLL.
|
|
* WARNING : If you use this program under a real NT descendant, be
|
|
* WARNING : sure to have disabled the PSX subsystem.
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* This software is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING. If not, write
|
|
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
|
|
* MA 02139, USA.
|
|
*
|
|
* --------------------------------------------------------------------
|
|
* 2002-03-16 EA Today it actually compiled.
|
|
* 2002-06-08 EA Renamed (old name was CSRTERM)
|
|
*/
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#define NTOS_MODE_USER
|
|
#include <ntos.h>
|
|
#include <sm/helper.h>
|
|
#include <psx/lpcproto.h>
|
|
|
|
#include "vt100.h"
|
|
#include "posixw32.h"
|
|
|
|
/*** OPTIONS *********************************************************/
|
|
|
|
#define PRIVATE static
|
|
|
|
#define INPUT_QUEUE_SIZE 32
|
|
|
|
#ifdef NDEBUG
|
|
#define TRACE
|
|
#else
|
|
//#define TRACE OutputDebugString(__FUNCTION__)
|
|
#define TRACE vtprintf("%s\n",__FUNCTION__)
|
|
#endif
|
|
|
|
/*** GLOBALS *********************************************************/
|
|
|
|
PRIVATE LPCSTR MyName = "POSIXW32";
|
|
PRIVATE CSRTERM_SESSION Session =
|
|
{
|
|
0, //Identifier
|
|
{ //ServerPort
|
|
{0,0,NULL},
|
|
L"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME"\\"PSX_NS_SESSIONAPI_PORT_NAME,
|
|
INVALID_HANDLE_VALUE
|
|
}
|
|
};
|
|
|
|
/*** PRIVATE FUNCTIONS ***********************************************/
|
|
VOID STDCALL Debug_Print (LPCSTR Format, ...)
|
|
{
|
|
CHAR Buffer [512];
|
|
va_list ArgumentPointer;
|
|
|
|
va_start(ArgumentPointer, Format);
|
|
vsprintf(Buffer, Format, ArgumentPointer);
|
|
va_end(ArgumentPointer);
|
|
OutputDebugStringA (Buffer);
|
|
}
|
|
/**********************************************************************
|
|
* OutPort/2 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Notify to PSXSS that input data is ready by sending a
|
|
* software interrupt on the \POSIX+\SessionPort port.
|
|
*/
|
|
PRIVATE DWORD STDCALL OutPort (PCHAR Buffer, ULONG Size)
|
|
{
|
|
NTSTATUS Status;
|
|
PSX_TERMINAL_READ TerminalRead;
|
|
TRACE;
|
|
if (Size > 0)
|
|
{
|
|
/* LPC */
|
|
TerminalRead.Header.MessageType = LPC_NEW_MESSAGE;
|
|
TerminalRead.PsxHeader.Context = PSX_CONNECTION_TYPE_TERMINAL;
|
|
TerminalRead.PsxHeader.Procedure = PSX_TERMINAL_INTERRUPT;
|
|
/* Terminal I/O */
|
|
TerminalRead.Size = Size;
|
|
#if 0
|
|
RtlCopyMemory (TerminalRead.Buffer, Buffer, Size);
|
|
Status = NtRequestWaitReplyPort (
|
|
Session.ServerPort.Handle,
|
|
& TerminalRead
|
|
/* FIXME */
|
|
);
|
|
#endif
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return 0;
|
|
}
|
|
}
|
|
return Size;
|
|
}
|
|
/**********************************************************************
|
|
* ProcessConnectionRequest/1 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Initialize our data for managing the control connection
|
|
* initiated by the PSXSS.EXE process.
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL ProcessConnectionRequest (PLPC_MAX_MESSAGE Request)
|
|
{
|
|
PPSX_CONNECT_PORT_DATA ConnectData = (PPSX_CONNECT_PORT_DATA) & Request->Data;
|
|
|
|
TRACE;
|
|
if (PSX_CONNECTION_TYPE_SERVER != ConnectData->ConnectionType)
|
|
{
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
if (PSX_LPC_PROTOCOL_VERSION != ConnectData->Version)
|
|
{
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
Session.SsLinkIsActive = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/**********************************************************************
|
|
* ProcessRequest/1 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL ProcessRequest (PPSX_MAX_MESSAGE Request)
|
|
{
|
|
TRACE;
|
|
/* TODO */
|
|
vtprintf("TEST VT-100\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/**********************************************************************
|
|
* PsxSessionPortListener/1 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Manage messages from the PSXSS, that is LPC messages we get
|
|
* from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
|
|
*
|
|
* NOTE
|
|
* This function is the thread 's entry point created in
|
|
* CreateSessionObiects().
|
|
*/
|
|
PRIVATE DWORD STDCALL PsxSessionPortListener (LPVOID Arg)
|
|
{
|
|
NTSTATUS Status;
|
|
LPC_TYPE RequestType;
|
|
PSX_MAX_MESSAGE Request;
|
|
PPSX_MAX_MESSAGE Reply = NULL;
|
|
BOOL NullReply = FALSE;
|
|
|
|
TRACE;
|
|
|
|
while (TRUE)
|
|
{
|
|
Reply = NULL;
|
|
NullReply = FALSE;
|
|
while (!NullReply)
|
|
{
|
|
Status = NtReplyWaitReceivePort (
|
|
Session.Port.Handle,
|
|
0,
|
|
(PLPC_MESSAGE) Reply,
|
|
(PLPC_MESSAGE) & Request
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
break;
|
|
}
|
|
RequestType = PORT_MESSAGE_TYPE(Request);
|
|
switch (RequestType)
|
|
{
|
|
case LPC_CONNECTION_REQUEST:
|
|
ProcessConnectionRequest ((PLPC_MAX_MESSAGE) & Request);
|
|
NullReply = TRUE;
|
|
continue;
|
|
case LPC_CLIENT_DIED:
|
|
case LPC_PORT_CLOSED:
|
|
case LPC_DEBUG_EVENT:
|
|
case LPC_ERROR_EVENT:
|
|
case LPC_EXCEPTION:
|
|
NullReply = TRUE;
|
|
continue;
|
|
default:
|
|
if (RequestType != LPC_REQUEST)
|
|
{
|
|
NullReply = TRUE;
|
|
continue;
|
|
}
|
|
}
|
|
Reply = & Request;
|
|
Reply->PsxHeader.Status = ProcessRequest (& Request);
|
|
NullReply = FALSE;
|
|
}
|
|
if ((STATUS_INVALID_HANDLE == Status) ||
|
|
(STATUS_OBJECT_TYPE_MISMATCH == Status))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
Session.SsLinkIsActive = FALSE;
|
|
TerminateThread (GetCurrentThread(), Status);
|
|
}
|
|
/**********************************************************************
|
|
* CreateSessionObiects/1 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Create the session objects which are mananged by our side:
|
|
*
|
|
* \POSIX+\Sessions\P<pid>
|
|
* \POSIX+\Sessions\D<pid>
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL CreateSessionObjects (DWORD Pid)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG Id = 0;
|
|
OBJECT_ATTRIBUTES Oa;
|
|
LARGE_INTEGER SectionSize = {PSX_TERMINAL_SECTION_SIZE,0};
|
|
|
|
TRACE;
|
|
|
|
|
|
/* Critical section */
|
|
Status = RtlInitializeCriticalSection (& Session.Lock);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
vtprintf (
|
|
"%s: %s: RtlInitializeCriticalSection failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
/* Port and port management thread */
|
|
swprintf (
|
|
Session.Port.NameBuffer,
|
|
PSX_NS_SESSION_PORT_TEMPLATE,
|
|
PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
|
|
PSX_NS_SESSION_DIRECTORY_NAME,
|
|
Pid
|
|
);
|
|
OutputDebugStringW(Session.Port.NameBuffer);
|
|
RtlInitUnicodeString (& Session.Port.Name, Session.Port.NameBuffer);
|
|
InitializeObjectAttributes (& Oa, & Session.Port.Name, 0, NULL, NULL);
|
|
Status = NtCreatePort (& Session.Port.Handle, & Oa, 0, 0, 0x10000);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
RtlDeleteCriticalSection (& Session.Lock);
|
|
vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
Session.Port.Thread.Handle =
|
|
CreateThread (
|
|
NULL,
|
|
0,
|
|
PsxSessionPortListener,
|
|
0,
|
|
CREATE_SUSPENDED,
|
|
& Session.Port.Thread.Id
|
|
);
|
|
if ((HANDLE) NULL == Session.Port.Thread.Handle)
|
|
{
|
|
Status = (NTSTATUS) GetLastError();
|
|
NtClose (Session.Port.Handle);
|
|
RtlDeleteCriticalSection (& Session.Lock);
|
|
vtprintf ("%s: %s: CreateThread failed with %d\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
/* Section */
|
|
swprintf (
|
|
Session.Section.NameBuffer,
|
|
PSX_NS_SESSION_DATA_TEMPLATE,
|
|
PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
|
|
PSX_NS_SESSION_DIRECTORY_NAME,
|
|
Pid
|
|
);
|
|
OutputDebugStringW(Session.Section.NameBuffer);
|
|
RtlInitUnicodeString (& Session.Section.Name, Session.Section.NameBuffer);
|
|
InitializeObjectAttributes (& Oa, & Session.Section.Name, 0, 0, 0);
|
|
Status = NtCreateSection (
|
|
& Session.Section.Handle,
|
|
SECTION_ALL_ACCESS, /* DesiredAccess */
|
|
& Oa,
|
|
& SectionSize,
|
|
PAGE_READWRITE, /* Protect 4 */
|
|
SEC_COMMIT, /* Attributes */
|
|
0 /* FileHandle: 0=pagefile.sys */
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
NtClose (Session.Port.Handle);
|
|
NtTerminateThread (Session.Port.Thread.Handle, Status);
|
|
RtlDeleteCriticalSection (& Session.Lock);
|
|
vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
Session.Section.BaseAddress = NULL;
|
|
Session.Section.ViewSize = SectionSize.u.LowPart;
|
|
Status = NtMapViewOfSection (
|
|
Session.Section.Handle,
|
|
NtCurrentProcess(),
|
|
& Session.Section.BaseAddress,
|
|
0, /* ZeroBits */
|
|
0, /* Commitsize */
|
|
0, /* SectionOffset */
|
|
& Session.Section.ViewSize,
|
|
ViewUnmap,
|
|
0, /* AllocationType */
|
|
PAGE_READWRITE /* Protect 4 */
|
|
);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
NtClose (Session.Port.Handle);
|
|
NtTerminateThread (Session.Port.Thread.Handle, Status);
|
|
NtClose (Session.Section.Handle);
|
|
RtlDeleteCriticalSection (& Session.Lock);
|
|
vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
return Status;
|
|
}
|
|
/**********************************************************************
|
|
* RunPsxSs/0
|
|
*
|
|
* DESCRIPTION
|
|
* This function is called only when initializing the session
|
|
* with PSXSS fails. We assume that it failed because the
|
|
* subsystem, being optional, is not running, therefore we
|
|
* ask the SM to start it up.
|
|
*/
|
|
PRIVATE NTSTATUS RunPsxSs(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE SmApiPort;
|
|
UNICODE_STRING Program;
|
|
|
|
RtlInitUnicodeString (& Program, L"POSIX");
|
|
Status = SmConnectApiPort (NULL, 0, 0, & SmApiPort);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
Status = SmExecuteProgram (SmApiPort, & Program);
|
|
NtClose (SmApiPort);
|
|
return Status;
|
|
}
|
|
/**********************************************************************
|
|
* CreateTerminalToPsxChannel/0 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
*
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL CreateTerminalToPsxChannel (VOID)
|
|
{
|
|
PSX_CONNECT_PORT_DATA ConnectData;
|
|
ULONG ConnectDataLength = sizeof ConnectData;
|
|
SECURITY_QUALITY_OF_SERVICE Sqos;
|
|
NTSTATUS Status;
|
|
LONG Count = 2;
|
|
|
|
TRACE;
|
|
|
|
|
|
/*
|
|
* Initialize the connection data object before
|
|
* calling PSXSS.
|
|
*/
|
|
ConnectData.ConnectionType = PSX_CONNECTION_TYPE_TERMINAL;
|
|
ConnectData.Version = PSX_LPC_PROTOCOL_VERSION;
|
|
/*
|
|
* Try connecting to \POSIX+\SessionPort.
|
|
*/
|
|
RtlInitUnicodeString (& Session.ServerPort.Name, Session.ServerPort.NameBuffer);
|
|
while (Count--)
|
|
{
|
|
OutputDebugStringW(Session.ServerPort.Name.Buffer);
|
|
Status = NtConnectPort (
|
|
& Session.ServerPort.Handle,
|
|
& Session.ServerPort.Name,
|
|
& Sqos,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
& ConnectData,
|
|
& ConnectDataLength
|
|
);
|
|
if (STATUS_SUCCESS != Status)
|
|
{
|
|
if(Count)
|
|
{
|
|
vtprintf("%s: %s: asking SM to start PSXSS...\n",MyName,__FUNCTION__);
|
|
RunPsxSs();
|
|
continue;
|
|
}
|
|
vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
break;
|
|
}
|
|
Session.Identifier = ConnectData.PortIdentifier;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/**********************************************************************
|
|
* InitializeSsIoChannel PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Connect to the session port (CreateControChannel) of the PSX
|
|
* subsystem. If that succeeds, create our objects in the system
|
|
* name space (CreateSessionObjects).
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
DWORD Pid = GetCurrentProcessId();
|
|
|
|
TRACE;
|
|
|
|
|
|
Status = CreateTerminalToPsxChannel ();
|
|
if (STATUS_SUCCESS != Status)
|
|
{
|
|
vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
Status = CreateSessionObjects (Pid);
|
|
if (STATUS_SUCCESS != Status)
|
|
{
|
|
vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
|
|
MyName, __FUNCTION__, Status);
|
|
return Status;
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/**********************************************************************
|
|
* PsxCreateLeaderProcess/1 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Create a new PSXSS process. We are running under Win32 server
|
|
* and can not run directly a PSX image: we make SM run it for us.
|
|
*
|
|
*/
|
|
PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
|
|
{
|
|
NTSTATUS Status;
|
|
TRACE;
|
|
|
|
if (NULL == Command)
|
|
{
|
|
Command = "sh";
|
|
}
|
|
/* TODO: request SM to create the process: LPC:SmExecPgm() */
|
|
vtprintf ("%s: %s: calling SMSS not implemented!", MyName, __FUNCTION__);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
/**********************************************************************
|
|
* PrintInformationProcess/0
|
|
*
|
|
* DESCRIPTION
|
|
*/
|
|
PRIVATE VOID STDCALL PrintInformationProcess (VOID)
|
|
{
|
|
|
|
TRACE;
|
|
|
|
vtputs ("Leader:");
|
|
vtprintf (" UniqueProcess %08x\n", Session.Client.UniqueProcess);
|
|
vtprintf (" UniqueThread %08x\n", Session.Client.UniqueThread);
|
|
}
|
|
/**********************************************************************
|
|
* PostMortem/0
|
|
*
|
|
* DESCRIPTION
|
|
*/
|
|
PRIVATE INT STDCALL PostMortem (VOID)
|
|
{
|
|
DWORD ExitCode;
|
|
|
|
TRACE;
|
|
|
|
|
|
PrintInformationProcess ();
|
|
if (TRUE == GetExitCodeProcess (Session.Client.UniqueProcess, & ExitCode))
|
|
{
|
|
vtprintf (" ExitCode %d\n", ExitCode);
|
|
}
|
|
return 0;
|
|
}
|
|
/**********************************************************************
|
|
* InputTerminalEmulator/0
|
|
*
|
|
* DESCRIPTION
|
|
* Process user terminal input.
|
|
*
|
|
* NOTE
|
|
* This code is run in the main thread.
|
|
*/
|
|
PRIVATE BOOL STDCALL InputTerminalEmulator (VOID)
|
|
{
|
|
HANDLE StandardInput;
|
|
INPUT_RECORD InputRecord [INPUT_QUEUE_SIZE];
|
|
DWORD NumberOfEventsRead = 0;
|
|
INT CurrentEvent;
|
|
|
|
|
|
TRACE;
|
|
|
|
StandardInput = GetStdHandle (STD_INPUT_HANDLE);
|
|
if (INVALID_HANDLE_VALUE == StandardInput)
|
|
{
|
|
return FALSE;
|
|
}
|
|
while ((TRUE == Session.SsLinkIsActive) &&
|
|
ReadConsoleInput (
|
|
StandardInput,
|
|
InputRecord,
|
|
(sizeof InputRecord) / sizeof (INPUT_RECORD),
|
|
& NumberOfEventsRead
|
|
))
|
|
{
|
|
for ( CurrentEvent = 0;
|
|
(CurrentEvent < NumberOfEventsRead);
|
|
CurrentEvent ++
|
|
)
|
|
{
|
|
switch (InputRecord [CurrentEvent].EventType)
|
|
{
|
|
case KEY_EVENT:
|
|
OutPort (& InputRecord [CurrentEvent].Event.KeyEvent.uChar.AsciiChar, 1);
|
|
break;
|
|
case MOUSE_EVENT:
|
|
/* TODO: send a sequence of move cursor codes */
|
|
/* InputRecord [CurrentEvent].Event.MouseEvent; */
|
|
break;
|
|
case WINDOW_BUFFER_SIZE_EVENT:
|
|
/* TODO: send a SIGWINCH signal to the leader process. */
|
|
/* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
|
|
break;
|
|
/* Next events should be ignored. */
|
|
case MENU_EVENT:
|
|
vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName, __FUNCTION__);
|
|
case FOCUS_EVENT:
|
|
vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName, __FUNCTION__);
|
|
break;
|
|
}
|
|
}
|
|
NumberOfEventsRead = 0;
|
|
}
|
|
return TRUE;
|
|
}
|
|
/**********************************************************************
|
|
* Startup/1
|
|
*
|
|
* DESCRIPTION
|
|
* Initialize the program.
|
|
*/
|
|
PRIVATE VOID STDCALL Startup (LPSTR Command)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD ThreadId;
|
|
|
|
|
|
TRACE;
|
|
|
|
/* PSX process info */
|
|
Session.Client.UniqueProcess = INVALID_HANDLE_VALUE;
|
|
Session.Client.UniqueThread = INVALID_HANDLE_VALUE;
|
|
/* Initialize the VT-100 emulator */
|
|
vtInitVT100 ();
|
|
/* Connect to PSXSS */
|
|
Status = InitializeSsIoChannel ();
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
|
|
MyName, Status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
/* Create the leading process for this session */
|
|
Status = PsxCreateLeaderProcess (Command);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
|
|
MyName, Status);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
/**********************************************************************
|
|
* Shutdown/0 PRIVATE
|
|
*
|
|
* DESCRIPTION
|
|
* Shutdown the program.
|
|
*/
|
|
PRIVATE INT STDCALL Shutdown (VOID)
|
|
{
|
|
|
|
TRACE;
|
|
|
|
/* TODO: try exiting cleanly: close any open resource */
|
|
/* TODO: notify PSXSS the session is terminating */
|
|
RtlDeleteCriticalSection (& Session.Lock);
|
|
return PostMortem ();
|
|
}
|
|
/**********************************************************************
|
|
*
|
|
* ENTRY POINT PUBLIC
|
|
*
|
|
*********************************************************************/
|
|
int main (int argc, char * argv [])
|
|
{
|
|
|
|
TRACE;
|
|
|
|
Startup (argv[1]); /* Initialization */
|
|
InputTerminalEmulator (); /* Process user input */
|
|
return Shutdown ();
|
|
}
|
|
/* EOF */
|