Eric Pouech : kernel32: Fixed a couple of cases where the console was not reset in cooked mode after a bare console has been created .

Alexandre Julliard julliard at winehq.org
Mon Sep 13 17:14:45 CDT 2010


Module: wine
Branch: master
Commit: a2322e3735b04071fea80c6435da33e315b3b1a2
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=a2322e3735b04071fea80c6435da33e315b3b1a2

Author: Eric Pouech <eric.pouech at orange.fr>
Date:   Fri Sep 10 21:50:19 2010 +0200

kernel32: Fixed a couple of cases where the console was not reset in cooked mode after a bare console has been created.

---

 dlls/kernel32/console.c        |  103 ++++++++++++++++++++++++++++++++++++++++
 dlls/kernel32/kernel_main.c    |    1 +
 dlls/kernel32/kernel_private.h |    1 +
 server/console.c               |   33 -------------
 4 files changed, 105 insertions(+), 33 deletions(-)

diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c
index 9ac7018..aa7f105 100644
--- a/dlls/kernel32/console.c
+++ b/dlls/kernel32/console.c
@@ -42,6 +42,8 @@
 # include <termios.h>
 #endif
 
+#include "ntstatus.h"
+#define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
 #include "winnls.h"
@@ -146,6 +148,96 @@ static BOOL get_console_mode(HANDLE conin, DWORD* mode, BOOL* bare)
     return ret;
 }
 
+static struct termios S_termios;        /* saved termios for bare consoles */
+static BOOL S_termios_raw /* = FALSE */;
+
+/* The scheme for bare consoles for managing raw/cooked settings is as follows:
+ * - a bare console is created for all CUI programs started from command line (without
+ *   wineconsole) (let's call those PS)
+ * - of course, every child of a PS which requires console inheritance will get it
+ * - the console termios attributes are saved at the start of program which is attached to be
+ *   bare console
+ * - if any program attached to a bare console requests input from console, the console is
+ *   turned into raw mode
+ * - when the program which created the bare console (the program started from command line)
+ *   exits, it will restore the console termios attributes it saved at startup (this
+ *   will put back the console into cooked mode if it had been put in raw mode)
+ * - if any other program attached to this bare console is still alive, the Unix shell will put
+ *   it in the background, hence forbidding access to the console. Therefore, reading console
+ *   input will not be available when the bare console creator has died.
+ *   FIXME: This is a limitation of current implementation
+ */
+
+/* returns the fd for a bare console (-1 otherwise) */
+static int  get_console_bare_fd(HANDLE hin)
+{
+    BOOL        is_bare;
+    int         fd;
+
+    if (get_console_mode(hin, NULL, &is_bare) && is_bare &&
+        wine_server_handle_to_fd(hin, 0, &fd, NULL) == STATUS_SUCCESS)
+        return fd;
+    return -1;
+}
+
+static BOOL save_console_mode(HANDLE hin)
+{
+    int         fd;
+    BOOL        ret;
+
+    if ((fd = get_console_bare_fd(hin)) == -1) return FALSE;
+    ret = tcgetattr(fd, &S_termios) >= 0;
+    close(fd);
+    return ret;
+}
+
+static BOOL put_console_into_raw_mode(HANDLE hin)
+{
+    int            fd;
+
+    if ((fd = get_console_bare_fd(hin)) == -1) return FALSE;
+
+    RtlEnterCriticalSection(&CONSOLE_CritSect);
+    if (!S_termios_raw)
+    {
+        struct termios term = S_termios;
+
+        term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
+        term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+        term.c_cflag &= ~(CSIZE | PARENB);
+        term.c_cflag |= CS8;
+        /* FIXME: we should actually disable output processing here
+         * and let kernel32/console.c do the job (with support of enable/disable of
+         * processed output)
+         */
+        /* term.c_oflag &= ~(OPOST); */
+        term.c_cc[VMIN] = 1;
+        term.c_cc[VTIME] = 0;
+        S_termios_raw = tcsetattr(fd, TCSANOW, &term) >= 0;
+    }
+    RtlLeaveCriticalSection(&CONSOLE_CritSect);
+
+    close(fd);
+    return S_termios_raw;
+}
+
+/* put back the console in cooked mode iff we're the process which created the bare console
+ * we don't test if thie process has set the console in raw mode as it could be one of its
+ * child who did it
+ */
+static BOOL restore_console_mode(HANDLE hin)
+{
+    int         fd;
+    BOOL        ret;
+
+    if (RtlGetCurrentPeb()->ProcessParameters->ConsoleHandle != KERNEL32_CONSOLE_SHELL)
+        return TRUE;
+    if ((fd = get_console_bare_fd(hin)) == -1) return FALSE;
+    ret = tcsetattr(fd, TCSANOW, &S_termios) >= 0;
+    close(fd);
+    return ret;
+}
+
 /******************************************************************************
  * GetConsoleWindow [KERNEL32.@] Get hwnd of the console window.
  *
@@ -1080,6 +1172,7 @@ static enum read_console_input_return read_console_input(HANDLE handle, PINPUT_R
 
     if (bare)
     {
+        put_console_into_raw_mode(handle);
         if (WaitForSingleObject(GetConsoleInputWaitHandle(), 0) != WAIT_OBJECT_0)
         {
             ret = bare_console_fetch_input(handle, timeout);
@@ -2893,6 +2986,7 @@ DWORD WINAPI GetConsoleProcessList(LPDWORD processlist, DWORD processcount)
 
 BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params)
 {
+    memset(&S_termios, 0, sizeof(S_termios));
     if (params->ConsoleHandle == KERNEL32_CONSOLE_SHELL)
     {
         HANDLE  conin;
@@ -2956,7 +3050,10 @@ BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params)
     if (!params->hStdInput)
         params->hStdInput = INVALID_HANDLE_VALUE;
     else if (VerifyConsoleIoHandle(console_handle_map(params->hStdInput)))
+    {
         params->hStdInput = console_handle_map(params->hStdInput);
+        save_console_mode(params->hStdInput);
+    }
 
     if (!params->hStdOutput)
         params->hStdOutput = INVALID_HANDLE_VALUE;
@@ -2970,3 +3067,9 @@ BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params)
 
     return TRUE;
 }
+
+BOOL CONSOLE_Exit(void)
+{
+    /* the console is in raw mode, put it back in cooked mode */
+    return restore_console_mode(GetStdHandle(STD_INPUT_HANDLE));
+}
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c
index 41647dd..42d038e 100644
--- a/dlls/kernel32/kernel_main.c
+++ b/dlls/kernel32/kernel_main.c
@@ -138,6 +138,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
         return process_attach( hinst );
     case DLL_PROCESS_DETACH:
         WritePrivateProfileSectionW( NULL, NULL, NULL );
+        CONSOLE_Exit();
         break;
     }
     return TRUE;
diff --git a/dlls/kernel32/kernel_private.h b/dlls/kernel32/kernel_private.h
index f741a92..f180e7d 100644
--- a/dlls/kernel32/kernel_private.h
+++ b/dlls/kernel32/kernel_private.h
@@ -29,6 +29,7 @@ HANDLE  WINAPI DuplicateConsoleHandle(HANDLE, DWORD, BOOL, DWORD);
 BOOL    WINAPI CloseConsoleHandle(HANDLE handle);
 HANDLE  WINAPI GetConsoleInputWaitHandle(void);
 BOOL           CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params);
+BOOL           CONSOLE_Exit(void);
 
 static inline BOOL is_console_handle(HANDLE h)
 {
diff --git a/server/console.c b/server/console.c
index 2ca6bd4..6616bd2 100644
--- a/server/console.c
+++ b/server/console.c
@@ -28,9 +28,6 @@
 #include <stdio.h>
 #include <unistd.h>
 #include <signal.h>
-#ifdef HAVE_TERMIOS_H
-#include <termios.h>
-#endif
 
 #include "ntstatus.h"
 #define WIN32_NO_STATUS
@@ -66,7 +63,6 @@ struct console_input
     user_handle_t                win;           /* window handle if backend supports it */
     struct event                *event;         /* event to wait on for input queue */
     struct fd                   *fd;            /* for bare console, attached input fd */
-    struct termios               termios;       /* for bare console, saved termio info */
 };
 
 static void console_input_dump( struct object *obj, int verbose );
@@ -328,38 +324,12 @@ static struct object *create_console_input( struct thread* renderer, int fd )
     }
     if (fd != -1) /* bare console */
     {
-        struct termios  term;
-
         if (!(console_input->fd = create_anonymous_fd( &console_fd_ops, fd, &console_input->obj,
                                                        FILE_SYNCHRONOUS_IO_NONALERT )))
         {
             release_object( console_input );
             return NULL;
         }
-        if (tcgetattr(fd, &term) < 0)
-        {
-            release_object( console_input );
-            set_error( STATUS_INVALID_HANDLE );
-            return NULL;
-        }
-        console_input->termios = term;
-        term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
-        term.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
-        term.c_cflag &= ~(CSIZE | PARENB);
-        term.c_cflag |= CS8;
-        /* FIXME: we should actually disable output processing here
-         * and let kernel32/console.c do the job (with support of enable/disable of
-         * processed output)
-         */
-        /* term.c_oflag &= ~(OPOST); */
-        term.c_cc[VMIN] = 1;
-        term.c_cc[VTIME] = 0;
-        if (tcsetattr(fd, TCSANOW, &term) < 0)
-        {
-            release_object( console_input );
-            set_error( STATUS_INVALID_HANDLE );
-            return NULL;
-        }
         allow_fd_caching( console_input->fd );
     }
 
@@ -1129,10 +1099,7 @@ static void console_input_destroy( struct object *obj )
     }
     release_object( console_in->event );
     if (console_in->fd)
-    {
-        tcsetattr(get_unix_fd(console_in->fd), TCSANOW, &console_in->termios);
         release_object( console_in->fd );
-    }
 
     for (i = 0; i < console_in->history_size; i++)
         free( console_in->history[i] );




More information about the wine-cvs mailing list