Module: wine
Branch: master
Commit: a2322e3735b04071fea80c6435da33e315b3b1a2
URL: http://source.winehq.org/git/wine.git/?a=commit;h=a2322e3735b04071fea80c643…
Author: Eric Pouech <eric.pouech(a)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] );