PSXSS: It seems the renamed csrterm did not get in the repository.
[reactos.git] / posix / apps / posixw32 / posixw32.c
diff --git a/posix/apps/posixw32/posixw32.c b/posix/apps/posixw32/posixw32.c
new file mode 100644 (file)
index 0000000..4979938
--- /dev/null
@@ -0,0 +1,610 @@
+/* $Id: posixw32.c,v 1.1 2002/06/09 08:37:07 ea Exp $
+ *
+ * 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 <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__)
+#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;
+}
+
+/**********************************************************************
+ *     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;
+
+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);
+    OutputDebugStringW(Session.ServerPort.Name.Buffer);
+    Status = NtConnectPort (
+                & Session.ServerPort.Handle,
+                & Session.ServerPort.Name,
+                & Sqos,
+                NULL,
+                NULL,
+                0,
+                & ConnectData,
+                & ConnectDataLength
+                );
+    if (STATUS_SUCCESS != Status)
+    {
+        vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
+            MyName, __FUNCTION__, Status);
+        return Status;
+    }
+    Session.Identifier = ConnectData.PortIdentifier;
+    return STATUS_SUCCESS;
+}
+
+/**********************************************************************
+ *     InitializeSsIoChannel                                   PRIVATE
+ *
+ * DESCRIPTION
+ *     Create our objects in the system name space
+ *     (CreateSessionObjects) and then connect to the session port
+ *     (CreateControChannel).
+ */
+PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
+{
+       NTSTATUS  Status = STATUS_SUCCESS;
+       DWORD     Pid = GetCurrentProcessId();
+
+TRACE;
+
+
+       Status = CreateSessionObjects (Pid);
+       if (STATUS_SUCCESS != Status)
+       {
+               vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
+                    MyName, __FUNCTION__, Status);
+               return Status;
+       }
+       Status = CreateTerminalToPsxChannel ();
+       if (STATUS_SUCCESS != Status)
+       {
+               vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
+                   MyName, __FUNCTION__, Status);
+               return Status;
+       }
+       return STATUS_SUCCESS;
+}
+/**********************************************************************
+ *     PsxCreateLeaderProcess/1                                PRIVATE
+ *
+ * DESCRIPTION
+ *     Create a new PSXSS process.
+ */
+PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
+{
+        NTSTATUS Status;
+TRACE;
+
+       if (NULL == Command)
+       {
+               Command = "sh";
+       }
+       /* TODO: request PSXSS to init the process slot */
+       vtprintf ("%s: %s: calling CSRSS 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 */