PSX: POSIXW32: I updated a note about creating a PSX process from W32.
[reactos.git] / posix / apps / posixw32 / posixw32.c
1 /* $Id: posixw32.c,v 1.4 2003/08/28 20:01:23 ea Exp $
2 *
3 * PROJECT : ReactOS Operating System / POSIX+ Environment Subsystem
4 * DESCRIPTION: POSIXW32 - A DEC VT-100 terminal emulator for the PSX subsystem
5 * DESCRIPTION: that runs in the Win32 subsystem.
6 * COPYRIGHT : Copyright (c) 2001-2002 Emanuele Aliberti
7 * LICENSE : GNU GPL v2
8 * DATE : 2001-05-05
9 * AUTHOR : Emanuele Aliberti <ea@iol.it>
10 * NOTE : This IS a Win32 program, but will fail if the PSX subsystem
11 * NOTE : is not installed. The PSX subsystem consists of two more
12 * NOTE : files: PSXSS.EXE, PSXDLL.DLL.
13 * WARNING : If you use this program under a real NT descendant, be
14 * WARNING : sure to have disabled the PSX subsystem.
15 * --------------------------------------------------------------------
16 *
17 * This software is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License as
19 * published by the Free Software Foundation; either version 2 of the
20 * License, or (at your option) any later version.
21 *
22 * This software is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this software; see the file COPYING. If not, write
29 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
30 * MA 02139, USA.
31 *
32 * --------------------------------------------------------------------
33 * 2002-03-16 EA Today it actually compiled.
34 * 2002-06-08 EA Renamed (old name was CSRTERM)
35 */
36 #include <windows.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39
40 #define NTOS_MODE_USER
41 #include <ntos.h>
42 #include <psx/lpcproto.h>
43
44 #include "vt100.h"
45 #include "posixw32.h"
46
47 /*** OPTIONS *********************************************************/
48
49 #define PRIVATE static
50
51 #define INPUT_QUEUE_SIZE 32
52
53 #ifdef NDEBUG
54 #define TRACE
55 #else
56 #define TRACE OutputDebugString(__FUNCTION__)
57 #endif
58
59 /*** GLOBALS *********************************************************/
60
61 PRIVATE LPCSTR MyName = "POSIXW32";
62 PRIVATE CSRTERM_SESSION Session =
63 {
64 0, //Identifier
65 { //ServerPort
66 {0,0,NULL},
67 L"\\"PSX_NS_SUBSYSTEM_DIRECTORY_NAME"\\"PSX_NS_SESSIONAPI_PORT_NAME,
68 INVALID_HANDLE_VALUE
69 }
70 };
71
72 /*** PRIVATE FUNCTIONS ***********************************************/
73 VOID STDCALL Debug_Print (LPCSTR Format, ...)
74 {
75 CHAR Buffer [512];
76 va_list ArgumentPointer;
77
78 va_start(ArgumentPointer, Format);
79 vsprintf(Buffer, Format, ArgumentPointer);
80 va_end(ArgumentPointer);
81 OutputDebugStringA (Buffer);
82 }
83 /**********************************************************************
84 * OutPort/2 PRIVATE
85 *
86 * DESCRIPTION
87 * Notify to PSXSS that input data is ready by sending a
88 * software interrupt on the \POSIX+\SessionPort port.
89 */
90 PRIVATE DWORD STDCALL OutPort (PCHAR Buffer, ULONG Size)
91 {
92 NTSTATUS Status;
93 PSX_TERMINAL_READ TerminalRead;
94 TRACE;
95 if (Size > 0)
96 {
97 /* LPC */
98 TerminalRead.Header.MessageType = LPC_NEW_MESSAGE;
99 TerminalRead.PsxHeader.Context = PSX_CONNECTION_TYPE_TERMINAL;
100 TerminalRead.PsxHeader.Procedure = PSX_TERMINAL_INTERRUPT;
101 /* Terminal I/O */
102 TerminalRead.Size = Size;
103 #if 0
104 RtlCopyMemory (TerminalRead.Buffer, Buffer, Size);
105 Status = NtRequestWaitReplyPort (
106 Session.ServerPort.Handle,
107 & TerminalRead
108 /* FIXME */
109 );
110 #endif
111 if (!NT_SUCCESS(Status))
112 {
113 vtprintf ("%s: %s: NtRequestWaitReplyPort failed with %08x\n",
114 MyName, __FUNCTION__, Status);
115 return 0;
116 }
117 }
118 return Size;
119 }
120 /**********************************************************************
121 * ProcessConnectionRequest/1 PRIVATE
122 *
123 * DESCRIPTION
124 * Initialize our data for managing the control connection
125 * initiated by the PSXSS.EXE process.
126 */
127 PRIVATE NTSTATUS STDCALL ProcessConnectionRequest (PLPC_MAX_MESSAGE Request)
128 {
129 PPSX_CONNECT_PORT_DATA ConnectData = (PPSX_CONNECT_PORT_DATA) & Request->Data;
130
131 TRACE;
132 if (PSX_CONNECTION_TYPE_SERVER != ConnectData->ConnectionType)
133 {
134
135 return STATUS_UNSUCCESSFUL;
136 }
137 if (PSX_LPC_PROTOCOL_VERSION != ConnectData->Version)
138 {
139
140 return STATUS_UNSUCCESSFUL;
141 }
142 Session.SsLinkIsActive = TRUE;
143 return STATUS_SUCCESS;
144 }
145 /**********************************************************************
146 * ProcessRequest/1 PRIVATE
147 *
148 * DESCRIPTION
149 *
150 */
151 PRIVATE NTSTATUS STDCALL ProcessRequest (PPSX_MAX_MESSAGE Request)
152 {
153 TRACE;
154 /* TODO */
155 vtprintf("TEST VT-100\n");
156
157 return STATUS_SUCCESS;
158 }
159 /**********************************************************************
160 * PsxSessionPortListener/1 PRIVATE
161 *
162 * DESCRIPTION
163 * Manage messages from the PSXSS, that is LPC messages we get
164 * from the PSXSS process to our \POSIX+\Sessions\P<pid> port.
165 *
166 * NOTE
167 * This function is the thread 's entry point created in
168 * CreateSessionObiects().
169 */
170 PRIVATE DWORD STDCALL PsxSessionPortListener (LPVOID Arg)
171 {
172 NTSTATUS Status;
173 LPC_TYPE RequestType;
174 PSX_MAX_MESSAGE Request;
175 PPSX_MAX_MESSAGE Reply = NULL;
176 BOOL NullReply = FALSE;
177
178 TRACE;
179
180 while (TRUE)
181 {
182 Reply = NULL;
183 NullReply = FALSE;
184 while (!NullReply)
185 {
186 Status = NtReplyWaitReceivePort (
187 Session.Port.Handle,
188 0,
189 (PLPC_MESSAGE) Reply,
190 (PLPC_MESSAGE) & Request
191 );
192 if (!NT_SUCCESS(Status))
193 {
194 break;
195 }
196 RequestType = PORT_MESSAGE_TYPE(Request);
197 switch (RequestType)
198 {
199 case LPC_CONNECTION_REQUEST:
200 ProcessConnectionRequest ((PLPC_MAX_MESSAGE) & Request);
201 NullReply = TRUE;
202 continue;
203 case LPC_CLIENT_DIED:
204 case LPC_PORT_CLOSED:
205 case LPC_DEBUG_EVENT:
206 case LPC_ERROR_EVENT:
207 case LPC_EXCEPTION:
208 NullReply = TRUE;
209 continue;
210 default:
211 if (RequestType != LPC_REQUEST)
212 {
213 NullReply = TRUE;
214 continue;
215 }
216 }
217 Reply = & Request;
218 Reply->PsxHeader.Status = ProcessRequest (& Request);
219 NullReply = FALSE;
220 }
221 if ((STATUS_INVALID_HANDLE == Status) ||
222 (STATUS_OBJECT_TYPE_MISMATCH == Status))
223 {
224 break;
225 }
226 }
227 Session.SsLinkIsActive = FALSE;
228 TerminateThread (GetCurrentThread(), Status);
229 }
230 /**********************************************************************
231 * CreateSessionObiects/1 PRIVATE
232 *
233 * DESCRIPTION
234 * Create the session objects which are mananged by our side:
235 *
236 * \POSIX+\Sessions\P<pid>
237 * \POSIX+\Sessions\D<pid>
238 */
239 PRIVATE NTSTATUS STDCALL CreateSessionObjects (DWORD Pid)
240 {
241 NTSTATUS Status;
242 ULONG Id = 0;
243 OBJECT_ATTRIBUTES Oa;
244 LARGE_INTEGER SectionSize = {PSX_TERMINAL_SECTION_SIZE,0};
245
246 TRACE;
247
248
249 /* Critical section */
250 Status = RtlInitializeCriticalSection (& Session.Lock);
251 if (!NT_SUCCESS(Status))
252 {
253 vtprintf (
254 "%s: %s: RtlInitializeCriticalSection failed with %08x\n",
255 MyName, __FUNCTION__, Status);
256 return Status;
257 }
258 /* Port and port management thread */
259 swprintf (
260 Session.Port.NameBuffer,
261 PSX_NS_SESSION_PORT_TEMPLATE,
262 PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
263 PSX_NS_SESSION_DIRECTORY_NAME,
264 Pid
265 );
266 OutputDebugStringW(Session.Port.NameBuffer);
267 RtlInitUnicodeString (& Session.Port.Name, Session.Port.NameBuffer);
268 InitializeObjectAttributes (& Oa, & Session.Port.Name, 0, NULL, NULL);
269 Status = NtCreatePort (& Session.Port.Handle, & Oa, 0, 0, 0x10000);
270 if (!NT_SUCCESS(Status))
271 {
272 RtlDeleteCriticalSection (& Session.Lock);
273 vtprintf ("%s: %s: NtCreatePort failed with %08x\n",
274 MyName, __FUNCTION__, Status);
275 return Status;
276 }
277 Session.Port.Thread.Handle =
278 CreateThread (
279 NULL,
280 0,
281 PsxSessionPortListener,
282 0,
283 CREATE_SUSPENDED,
284 & Session.Port.Thread.Id
285 );
286 if ((HANDLE) NULL == Session.Port.Thread.Handle)
287 {
288 Status = (NTSTATUS) GetLastError();
289 NtClose (Session.Port.Handle);
290 RtlDeleteCriticalSection (& Session.Lock);
291 vtprintf ("%s: %s: CreateThread failed with %d\n",
292 MyName, __FUNCTION__, Status);
293 return Status;
294 }
295 /* Section */
296 swprintf (
297 Session.Section.NameBuffer,
298 PSX_NS_SESSION_DATA_TEMPLATE,
299 PSX_NS_SUBSYSTEM_DIRECTORY_NAME,
300 PSX_NS_SESSION_DIRECTORY_NAME,
301 Pid
302 );
303 OutputDebugStringW(Session.Section.NameBuffer);
304 RtlInitUnicodeString (& Session.Section.Name, Session.Section.NameBuffer);
305 InitializeObjectAttributes (& Oa, & Session.Section.Name, 0, 0, 0);
306 Status = NtCreateSection (
307 & Session.Section.Handle,
308 SECTION_ALL_ACCESS, /* DesiredAccess */
309 & Oa,
310 & SectionSize,
311 PAGE_READWRITE, /* Protect 4 */
312 SEC_COMMIT, /* Attributes */
313 0 /* FileHandle: 0=pagefile.sys */
314 );
315 if (!NT_SUCCESS(Status))
316 {
317 NtClose (Session.Port.Handle);
318 NtTerminateThread (Session.Port.Thread.Handle, Status);
319 RtlDeleteCriticalSection (& Session.Lock);
320 vtprintf ("%s: %s: NtCreateSection failed with %08x\n",
321 MyName, __FUNCTION__, Status);
322 return Status;
323 }
324 Session.Section.BaseAddress = NULL;
325 Session.Section.ViewSize = SectionSize.u.LowPart;
326 Status = NtMapViewOfSection (
327 Session.Section.Handle,
328 NtCurrentProcess(),
329 & Session.Section.BaseAddress,
330 0, /* ZeroBits */
331 0, /* Commitsize */
332 0, /* SectionOffset */
333 & Session.Section.ViewSize,
334 ViewUnmap,
335 0, /* AllocationType */
336 PAGE_READWRITE /* Protect 4 */
337 );
338 if (!NT_SUCCESS(Status))
339 {
340 NtClose (Session.Port.Handle);
341 NtTerminateThread (Session.Port.Thread.Handle, Status);
342 NtClose (Session.Section.Handle);
343 RtlDeleteCriticalSection (& Session.Lock);
344 vtprintf ("%s: %s: NtMapViewOfSection failed with %08x\n",
345 MyName, __FUNCTION__, Status);
346 return Status;
347 }
348 return Status;
349 }
350
351 /**********************************************************************
352 * CreateTerminalToPsxChannel/0 PRIVATE
353 *
354 * DESCRIPTION
355 *
356 */
357 PRIVATE NTSTATUS STDCALL CreateTerminalToPsxChannel (VOID)
358 {
359 PSX_CONNECT_PORT_DATA ConnectData;
360 ULONG ConnectDataLength = sizeof ConnectData;
361 SECURITY_QUALITY_OF_SERVICE Sqos;
362 NTSTATUS Status;
363
364 TRACE;
365
366
367 /*
368 * Initialize the connection data object before
369 * calling PSXSS.
370 */
371 ConnectData.ConnectionType = PSX_CONNECTION_TYPE_TERMINAL;
372 ConnectData.Version = PSX_LPC_PROTOCOL_VERSION;
373 /*
374 * Try connecting to \POSIX+\SessionPort.
375 */
376 RtlInitUnicodeString (& Session.ServerPort.Name, Session.ServerPort.NameBuffer);
377 OutputDebugStringW(Session.ServerPort.Name.Buffer);
378 Status = NtConnectPort (
379 & Session.ServerPort.Handle,
380 & Session.ServerPort.Name,
381 & Sqos,
382 NULL,
383 NULL,
384 0,
385 & ConnectData,
386 & ConnectDataLength
387 );
388 if (STATUS_SUCCESS != Status)
389 {
390 vtprintf ("%s: %s: NtConnectPort failed with %08x\n",
391 MyName, __FUNCTION__, Status);
392 return Status;
393 }
394 Session.Identifier = ConnectData.PortIdentifier;
395 return STATUS_SUCCESS;
396 }
397
398 /**********************************************************************
399 * InitializeSsIoChannel PRIVATE
400 *
401 * DESCRIPTION
402 * Create our objects in the system name space
403 * (CreateSessionObjects) and then connect to the session port
404 * (CreateControChannel).
405 */
406 PRIVATE NTSTATUS STDCALL InitializeSsIoChannel (VOID)
407 {
408 NTSTATUS Status = STATUS_SUCCESS;
409 DWORD Pid = GetCurrentProcessId();
410
411 TRACE;
412
413
414 Status = CreateSessionObjects (Pid);
415 if (STATUS_SUCCESS != Status)
416 {
417 vtprintf ("%s: %s: CreateSessionObjects failed with %08x\n",
418 MyName, __FUNCTION__, Status);
419 return Status;
420 }
421 Status = CreateTerminalToPsxChannel ();
422 if (STATUS_SUCCESS != Status)
423 {
424 vtprintf ("%s: %s: CreateTerminalToPsxChannel failed with %08x\n",
425 MyName, __FUNCTION__, Status);
426 return Status;
427 }
428 return STATUS_SUCCESS;
429 }
430 /**********************************************************************
431 * PsxCreateLeaderProcess/1 PRIVATE
432 *
433 * DESCRIPTION
434 * Create a new PSXSS process. We are running under Win32 server
435 * and can not run directly a PSX image: we make SM run it for us.
436 *
437 */
438 PRIVATE NTSTATUS STDCALL PsxCreateLeaderProcess (char * Command)
439 {
440 NTSTATUS Status;
441 TRACE;
442
443 if (NULL == Command)
444 {
445 Command = "sh";
446 }
447 /* TODO: request SM to create the process: LPC:SmExecPgm() */
448 vtprintf ("%s: %s: calling SMSS not implemented!", MyName, __FUNCTION__);
449 return STATUS_SUCCESS;
450 }
451 /**********************************************************************
452 * PrintInformationProcess/0
453 *
454 * DESCRIPTION
455 */
456 PRIVATE VOID STDCALL PrintInformationProcess (VOID)
457 {
458
459 TRACE;
460
461 vtputs ("Leader:");
462 vtprintf (" UniqueProcess %08x\n", Session.Client.UniqueProcess);
463 vtprintf (" UniqueThread %08x\n", Session.Client.UniqueThread);
464 }
465 /**********************************************************************
466 * PostMortem/0
467 *
468 * DESCRIPTION
469 */
470 PRIVATE INT STDCALL PostMortem (VOID)
471 {
472 DWORD ExitCode;
473
474 TRACE;
475
476
477 PrintInformationProcess ();
478 if (TRUE == GetExitCodeProcess (Session.Client.UniqueProcess, & ExitCode))
479 {
480 vtprintf (" ExitCode %d\n", ExitCode);
481 }
482 return 0;
483 }
484 /**********************************************************************
485 * InputTerminalEmulator/0
486 *
487 * DESCRIPTION
488 * Process user terminal input.
489 *
490 * NOTE
491 * This code is run in the main thread.
492 */
493 PRIVATE BOOL STDCALL InputTerminalEmulator (VOID)
494 {
495 HANDLE StandardInput;
496 INPUT_RECORD InputRecord [INPUT_QUEUE_SIZE];
497 DWORD NumberOfEventsRead = 0;
498 INT CurrentEvent;
499
500
501 TRACE;
502
503 StandardInput = GetStdHandle (STD_INPUT_HANDLE);
504 if (INVALID_HANDLE_VALUE == StandardInput)
505 {
506 return FALSE;
507 }
508 while ((TRUE == Session.SsLinkIsActive) &&
509 ReadConsoleInput (
510 StandardInput,
511 InputRecord,
512 (sizeof InputRecord) / sizeof (INPUT_RECORD),
513 & NumberOfEventsRead
514 ))
515 {
516 for ( CurrentEvent = 0;
517 (CurrentEvent < NumberOfEventsRead);
518 CurrentEvent ++
519 )
520 {
521 switch (InputRecord [CurrentEvent].EventType)
522 {
523 case KEY_EVENT:
524 OutPort (& InputRecord [CurrentEvent].Event.KeyEvent.uChar.AsciiChar, 1);
525 break;
526 case MOUSE_EVENT:
527 /* TODO: send a sequence of move cursor codes */
528 /* InputRecord [CurrentEvent].Event.MouseEvent; */
529 break;
530 case WINDOW_BUFFER_SIZE_EVENT:
531 /* TODO: send a SIGWINCH signal to the leader process. */
532 /* InputRecord [CurrentEvent].Event.WindowBufferSizeEvent.dwSize; */
533 break;
534 /* Next events should be ignored. */
535 case MENU_EVENT:
536 vtprintf ("%s: %s: MENU_EVENT received from CSRSS\n", MyName, __FUNCTION__);
537 case FOCUS_EVENT:
538 vtprintf ("%s: %s: FOCUS_EVENT received from CSRSS\n", MyName, __FUNCTION__);
539 break;
540 }
541 }
542 NumberOfEventsRead = 0;
543 }
544 return TRUE;
545 }
546 /**********************************************************************
547 * Startup/1
548 *
549 * DESCRIPTION
550 * Initialize the program.
551 */
552 PRIVATE VOID STDCALL Startup (LPSTR Command)
553 {
554 NTSTATUS Status;
555 DWORD ThreadId;
556
557
558 TRACE;
559
560 /* PSX process info */
561 Session.Client.UniqueProcess = INVALID_HANDLE_VALUE;
562 Session.Client.UniqueThread = INVALID_HANDLE_VALUE;
563 /* Initialize the VT-100 emulator */
564 vtInitVT100 ();
565 /* Connect to PSXSS */
566 Status = InitializeSsIoChannel ();
567 if (!NT_SUCCESS(Status))
568 {
569 vtprintf ("%s: failed to connect to PSXSS (Status=%08x)!\n",
570 MyName, Status);
571 exit (EXIT_FAILURE);
572 }
573 /* Create the leading process for this session */
574 Status = PsxCreateLeaderProcess (Command);
575 if (!NT_SUCCESS(Status))
576 {
577 vtprintf ("%s: failed to create the PSX process (Status=%08x)!\n",
578 MyName, Status);
579 exit (EXIT_FAILURE);
580 }
581 }
582 /**********************************************************************
583 * Shutdown/0 PRIVATE
584 *
585 * DESCRIPTION
586 * Shutdown the program.
587 */
588 PRIVATE INT STDCALL Shutdown (VOID)
589 {
590
591 TRACE;
592
593 /* TODO: try exiting cleanly: close any open resource */
594 /* TODO: notify PSXSS the session is terminating */
595 RtlDeleteCriticalSection (& Session.Lock);
596 return PostMortem ();
597 }
598 /**********************************************************************
599 *
600 * ENTRY POINT PUBLIC
601 *
602 *********************************************************************/
603 int main (int argc, char * argv [])
604 {
605
606 TRACE;
607
608 Startup (argv[1]); /* Initialization */
609 InputTerminalEmulator (); /* Process user input */
610 return Shutdown ();
611 }
612 /* EOF */