[PATCH 4/7] Force using wineconsole as input manager for the bare consoles
Eric Pouech
eric.pouech at orange.fr
Sat Dec 29 09:21:36 CST 2012
- all unix input reading for bare consoles is now moved to wineconsole in line mode
- output is still done on client side
- force startup of wineconsole as parent of all processes launched from command line, hence ensuring better terminal control
A+
---
dlls/kernel32/console.c | 309 ++------------------------------
dlls/kernel32/console_private.h | 3
dlls/kernel32/editline.c | 4
dlls/kernel32/kernel_main.c | 1
dlls/kernel32/kernel_private.h | 1
dlls/kernel32/process.c | 26 +++
include/wine/server_protocol.h | 4
programs/wineconsole/line.c | 16 +-
programs/wineconsole/winecon_private.h | 2
programs/wineconsole/wineconsole.c | 37 +++-
server/console.c | 83 ++-------
server/protocol.def | 1
server/request.h | 3
server/trace.c | 1
14 files changed, 112 insertions(+), 379 deletions(-)
diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c
index d6d1414..9ee3c14 100644
--- a/dlls/kernel32/console.c
+++ b/dlls/kernel32/console.c
@@ -37,13 +37,6 @@
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#include <assert.h>
-#ifdef HAVE_TERMIOS_H
-# include <termios.h>
-#endif
-#ifdef HAVE_SYS_POLL_H
-# include <sys/poll.h>
-#endif
#define NONAMELESSUNION
#include "ntstatus.h"
@@ -78,6 +71,20 @@ static const WCHAR conoutW[] = {'C','O','N','O','U','T','$',0};
/* FIXME: this is not thread safe */
static HANDLE console_wait_event;
+BOOL CONSOLE_is_handle_line_mode(HANDLE h)
+{
+ int fd;
+
+ if (is_console_handle(h) &&
+ wine_server_handle_to_fd(wine_server_ptr_handle(console_handle_unmap(h)),
+ 0, &fd, NULL) == STATUS_SUCCESS)
+ {
+ close(fd);
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* map input records to ASCII */
static void input_records_WtoA( INPUT_RECORD *buffer, int count )
{
@@ -135,93 +142,6 @@ static void char_info_AtoW( CHAR_INFO *buffer, int count )
}
}
-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)
-{
- int fd;
-
- if (is_console_handle(hin) &&
- wine_server_handle_to_fd(wine_server_ptr_handle(console_handle_unmap(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(int fd)
-{
- 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);
-
- 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 this process has set the console in raw mode as it could be one of its
- * children who did it
- */
-static BOOL restore_console_mode(HANDLE hin)
-{
- int fd;
- BOOL ret;
-
- if (!S_termios_raw ||
- 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);
- TERM_Exit();
- return ret;
-}
-
/******************************************************************************
* GetConsoleWindow [KERNEL32.@] Get hwnd of the console window.
*
@@ -1099,121 +1019,14 @@ BOOL WINAPI GetNumberOfConsoleInputEvents( HANDLE handle, LPDWORD nrofevents )
*/
enum read_console_input_return {rci_error = 0, rci_timeout = 1, rci_gotone = 2};
-static enum read_console_input_return bare_console_fetch_input(HANDLE handle, int fd, DWORD timeout)
-{
- enum read_console_input_return ret;
- char input[8];
- WCHAR inputw[8];
- int i;
- size_t idx = 0, idxw;
- unsigned numEvent;
- INPUT_RECORD ir[8];
- DWORD written;
- struct pollfd pollfd;
- BOOL locked = FALSE, next_char;
-
- do
- {
- if (idx == sizeof(input))
- {
- FIXME("buffer too small (%s)\n", wine_dbgstr_an(input, idx));
- ret = rci_error;
- break;
- }
- pollfd.fd = fd;
- pollfd.events = POLLIN;
- pollfd.revents = 0;
- next_char = FALSE;
-
- switch (poll(&pollfd, 1, timeout))
- {
- case 1:
- if (!locked)
- {
- RtlEnterCriticalSection(&CONSOLE_CritSect);
- locked = TRUE;
- }
- i = read(fd, &input[idx], 1);
- if (i < 0)
- {
- ret = rci_error;
- break;
- }
- if (i == 0)
- {
- /* actually another thread likely beat us to reading the char
- * return rci_gotone, while not perfect, it should work in most of the cases (as the new event
- * should be now in the queue, fed from the other thread)
- */
- ret = rci_gotone;
- break;
- }
-
- idx++;
- numEvent = TERM_FillInputRecord(input, idx, ir);
- switch (numEvent)
- {
- case 0:
- /* we need more char(s) to tell if it matches a key-db entry. wait 1/2s for next char */
- timeout = 500;
- next_char = TRUE;
- break;
- case -1:
- /* we haven't found the string into key-db, push full input string into server */
- idxw = MultiByteToWideChar(CP_UNIXCP, 0, input, idx, inputw, sizeof(inputw) / sizeof(inputw[0]));
-
- /* we cannot translate yet... likely we need more chars (wait max 1/2s for next char) */
- if (idxw == 0)
- {
- timeout = 500;
- next_char = TRUE;
- break;
- }
- for (i = 0; i < idxw; i++)
- {
- numEvent = TERM_FillSimpleChar(inputw[i], ir);
- WriteConsoleInputW(handle, ir, numEvent, &written);
- }
- ret = rci_gotone;
- break;
- default:
- /* we got a transformation from key-db... push this into server */
- ret = WriteConsoleInputW(handle, ir, numEvent, &written) ? rci_gotone : rci_error;
- break;
- }
- break;
- case 0: ret = rci_timeout; break;
- default: ret = rci_error; break;
- }
- } while (next_char);
- if (locked) RtlLeaveCriticalSection(&CONSOLE_CritSect);
-
- return ret;
-}
-
static enum read_console_input_return read_console_input(HANDLE handle, PINPUT_RECORD ir, DWORD timeout)
{
- int fd;
enum read_console_input_return ret;
- if ((fd = get_console_bare_fd(handle)) != -1)
- {
- put_console_into_raw_mode(fd);
- if (WaitForSingleObject(GetConsoleInputWaitHandle(), 0) != WAIT_OBJECT_0)
- {
- ret = bare_console_fetch_input(handle, fd, timeout);
- }
- else ret = rci_gotone;
- close(fd);
- if (ret != rci_gotone) return ret;
- }
- else
- {
- if (!VerifyConsoleIoHandle(handle)) return rci_error;
+ if (!VerifyConsoleIoHandle(handle)) return rci_error;
- if (WaitForSingleObject(GetConsoleInputWaitHandle(), timeout) != WAIT_OBJECT_0)
- return rci_timeout;
- }
+ if (WaitForSingleObject(GetConsoleInputWaitHandle(), timeout) != WAIT_OBJECT_0)
+ return rci_timeout;
SERVER_START_REQ( read_console_input )
{
@@ -1631,25 +1444,18 @@ BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
DWORD charsread;
LPWSTR xbuf = lpBuffer;
DWORD mode;
- BOOL is_bare = FALSE;
- int fd;
TRACE("(%p,%p,%d,%p,%p)\n",
hConsoleInput, lpBuffer, nNumberOfCharsToRead, lpNumberOfCharsRead, lpReserved);
if (!GetConsoleMode(hConsoleInput, &mode))
return FALSE;
- if ((fd = get_console_bare_fd(hConsoleInput)) != -1)
- {
- close(fd);
- is_bare = TRUE;
- }
if (mode & ENABLE_LINE_INPUT)
{
if (!S_EditString || S_EditString[S_EditStrPos] == 0)
{
HeapFree(GetProcessHeap(), 0, S_EditString);
- if (!(S_EditString = CONSOLE_Readline(hConsoleInput, !is_bare)))
+ if (!(S_EditString = CONSOLE_Readline(hConsoleInput)))
return FALSE;
S_EditStrPos = 0;
}
@@ -1671,7 +1477,7 @@ BOOL WINAPI ReadConsoleW(HANDLE hConsoleInput, LPVOID lpBuffer,
* that we should wait for at least one character (not key). --KS
*/
charsread = 0;
- do
+ do
{
if (read_console_input(hConsoleInput, &ir, timeout) != rci_gotone) break;
if (ir.EventType == KEY_EVENT && ir.Event.KeyEvent.bKeyDown &&
@@ -2357,7 +2163,7 @@ BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumber
DWORD nw = 0;
const WCHAR* psz = lpBuffer;
CONSOLE_SCREEN_BUFFER_INFO csbi;
- int k, first = 0, fd;
+ int k, first = 0;
TRACE("%p %s %d %p %p\n",
hConsoleOutput, debugstr_wn(lpBuffer, nNumberOfCharsToWrite),
@@ -2365,7 +2171,7 @@ BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumber
if (lpNumberOfCharsWritten) *lpNumberOfCharsWritten = 0;
- if ((fd = get_console_bare_fd(hConsoleOutput)) != -1)
+ if (CONSOLE_is_handle_line_mode(hConsoleOutput))
{
char* ptr;
unsigned len;
@@ -2373,9 +2179,9 @@ BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumber
NTSTATUS status;
IO_STATUS_BLOCK iosb;
- close(fd);
- /* FIXME: mode ENABLED_OUTPUT is not processed (or actually we rely on underlying Unix/TTY fd
- * to do the job
+ /* FIXME: mode ENABLE_PROCESSED_OUTPUT is not supported here
+ * (actually we rely on underlying Unix/TTY fd to do the job).
+ * Moreover, bare consoles are always in ENABLE_PROCESSED_OUTPUT mode
*/
len = WideCharToMultiByte(CP_UNIXCP, 0, lpBuffer, nNumberOfCharsToWrite, NULL, 0, NULL, NULL);
if ((ptr = HeapAlloc(GetProcessHeap(), 0, len)) == NULL)
@@ -3052,64 +2858,6 @@ 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;
-
- /* FIXME: to be done even if program is a GUI ? */
- /* This is wine specific: we have no parent (we're started from unix)
- * so, create a simple console with bare handles
- */
- TERM_Init();
- wine_server_send_fd(0);
- SERVER_START_REQ( alloc_console )
- {
- req->access = GENERIC_READ | GENERIC_WRITE;
- req->attributes = OBJ_INHERIT;
- req->pid = 0xffffffff;
- req->input_fd = 0;
- wine_server_call( req );
- conin = wine_server_ptr_handle( reply->handle_in );
- /* reply->event shouldn't be created by server */
- }
- SERVER_END_REQ;
-
- if (!params->hStdInput)
- params->hStdInput = conin;
-
- if (!params->hStdOutput)
- {
- wine_server_send_fd(1);
- SERVER_START_REQ( create_console_output )
- {
- req->handle_in = wine_server_obj_handle(conin);
- req->access = GENERIC_WRITE|GENERIC_READ;
- req->attributes = OBJ_INHERIT;
- req->share = FILE_SHARE_READ|FILE_SHARE_WRITE;
- req->fd = 1;
- wine_server_call(req);
- params->hStdOutput = wine_server_ptr_handle(reply->handle_out);
- }
- SERVER_END_REQ;
- }
- if (!params->hStdError)
- {
- wine_server_send_fd(2);
- SERVER_START_REQ( create_console_output )
- {
- req->handle_in = wine_server_obj_handle(conin);
- req->access = GENERIC_WRITE|GENERIC_READ;
- req->attributes = OBJ_INHERIT;
- req->share = FILE_SHARE_READ|FILE_SHARE_WRITE;
- req->fd = 2;
- wine_server_call(req);
- params->hStdError = wine_server_ptr_handle(reply->handle_out);
- }
- SERVER_END_REQ;
- }
- }
-
/* convert value from server:
* + 0 => INVALID_HANDLE_VALUE
* + console handle needs to be mapped
@@ -3117,10 +2865,7 @@ 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;
@@ -3135,12 +2880,6 @@ 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));
-}
-
/* Undocumented, called by native doskey.exe */
/* FIXME: Should use CONSOLE_GetHistory() above for full implementation */
DWORD WINAPI GetConsoleCommandHistoryA(DWORD unknown1, DWORD unknown2, DWORD unknown3)
diff --git a/dlls/kernel32/console_private.h b/dlls/kernel32/console_private.h
index dc48700..6faf08a 100644
--- a/dlls/kernel32/console_private.h
+++ b/dlls/kernel32/console_private.h
@@ -29,9 +29,10 @@ extern BOOL CONSOLE_AppendHistory(const WCHAR *p) DECLSPEC_HIDDEN;
extern unsigned CONSOLE_GetNumHistoryEntries(void) DECLSPEC_HIDDEN;
extern void CONSOLE_FillLineUniform(HANDLE hConsoleOutput, int i, int j, int len, LPCHAR_INFO lpFill) DECLSPEC_HIDDEN;
extern BOOL CONSOLE_GetEditionMode(HANDLE, int*) DECLSPEC_HIDDEN;
+extern BOOL CONSOLE_is_handle_line_mode(HANDLE hout) DECLSPEC_HIDDEN;
/* editline.c */
-extern WCHAR* CONSOLE_Readline(HANDLE, BOOL) DECLSPEC_HIDDEN;
+extern WCHAR* CONSOLE_Readline(HANDLE) DECLSPEC_HIDDEN;
/* term.c */
extern BOOL TERM_Init(void) DECLSPEC_HIDDEN;
diff --git a/dlls/kernel32/editline.c b/dlls/kernel32/editline.c
index 7664b55..2a69f86 100644
--- a/dlls/kernel32/editline.c
+++ b/dlls/kernel32/editline.c
@@ -912,7 +912,7 @@ static const KeyMap Win32KeyMap[] =
*
* ====================================================================*/
-WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, BOOL can_pos_cursor)
+WCHAR* CONSOLE_Readline(HANDLE hConsoleIn)
{
WCEL_Context ctx;
INPUT_RECORD ir;
@@ -939,7 +939,7 @@ WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, BOOL can_pos_cursor)
ctx.insert = (mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) == (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS) ? 1 : 0;
if (!GetConsoleMode(ctx.hConOut, &mode)) mode = 0;
ctx.can_wrap = (mode & ENABLE_WRAP_AT_EOL_OUTPUT) ? 1 : 0;
- ctx.can_pos_cursor = can_pos_cursor;
+ ctx.can_pos_cursor = !CONSOLE_is_handle_line_mode(ctx.hConOut);
if (!WCEL_Grow(&ctx, 1))
{
diff --git a/dlls/kernel32/kernel_main.c b/dlls/kernel32/kernel_main.c
index cf06765..43c5149 100644
--- a/dlls/kernel32/kernel_main.c
+++ b/dlls/kernel32/kernel_main.c
@@ -137,7 +137,6 @@ 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 feeeb55..a7d0135 100644
--- a/dlls/kernel32/kernel_private.h
+++ b/dlls/kernel32/kernel_private.h
@@ -29,7 +29,6 @@ HANDLE WINAPI DuplicateConsoleHandle(HANDLE, DWORD, BOOL, DWORD);
BOOL WINAPI CloseConsoleHandle(HANDLE handle);
HANDLE WINAPI GetConsoleInputWaitHandle(void);
BOOL CONSOLE_Init(RTL_USER_PROCESS_PARAMETERS *params) DECLSPEC_HIDDEN;
-BOOL CONSOLE_Exit(void) DECLSPEC_HIDDEN;
static inline BOOL is_console_handle(HANDLE h)
{
diff --git a/dlls/kernel32/process.c b/dlls/kernel32/process.c
index 3a88aaa..a444c94 100644
--- a/dlls/kernel32/process.c
+++ b/dlls/kernel32/process.c
@@ -1123,6 +1123,17 @@ static void set_process_name( int argc, char *argv[] )
}
}
+static int is_wineconsole(const char* name)
+{
+ const char *curr, *tmp;
+
+ /* get last wineconsole occurrence */
+ curr = name;
+ while ((tmp = strstr(curr, "wineconsole")) != NULL) curr = tmp + 11;
+ if (curr == name) return 0;
+ if (curr != name + 11 && curr[-12] != '/' && curr[-12] != '\\') return 0;
+ return *curr == '\0' || *curr == '.';
+}
/***********************************************************************
* __wine_kernel_init
@@ -1165,6 +1176,21 @@ void CDECL __wine_kernel_init(void)
init_current_directory( ¶ms->CurrentDirectory );
set_process_name( __wine_main_argc, __wine_main_argv );
+
+ /* If we've been started from command line (not from another Wine program),
+ * that we're attached to a unix console, and that we're not wineconsole,
+ * then force launch though wineconsole to get a proper console.
+ */
+ if (!peb->ProcessParameters->ImagePathName.Buffer &&
+ (isatty(0) || isatty(1) || isatty(2)) && !is_wineconsole(__wine_main_argv[0]))
+ {
+ char** new_argv = malloc( (__wine_main_argc + 2) * sizeof(*new_argv) );
+ new_argv[0] = strdup("wineconsole");
+ new_argv[1] = strdup("--backend=line");
+ memcpy( &new_argv[2], __wine_main_argv, __wine_main_argc * sizeof(*new_argv) );
+ __wine_main_argc += 2;
+ __wine_main_argv = new_argv;
+ }
set_library_wargv( __wine_main_argv );
boot_events[0] = boot_events[1] = 0;
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 2a181fc..a75cf21 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1487,8 +1487,6 @@ struct alloc_console_request
unsigned int access;
unsigned int attributes;
process_id_t pid;
- int input_fd;
- char __pad_28[4];
};
struct alloc_console_reply
{
@@ -5713,6 +5711,6 @@ union generic_reply
struct set_suspend_context_reply set_suspend_context_reply;
};
-#define SERVER_PROTOCOL_VERSION 437
+#define SERVER_PROTOCOL_VERSION 438
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/programs/wineconsole/line.c b/programs/wineconsole/line.c
index a6816f6..1c21769 100644
--- a/programs/wineconsole/line.c
+++ b/programs/wineconsole/line.c
@@ -67,6 +67,14 @@ struct inner_data_line
struct termios termios;
};
+static int WCLINE_output_fd = -1;
+
+static int WCLINE_putchar(int c)
+{
+ char ch = (char)c;
+ return write(WCLINE_output_fd, &ch, 1);
+}
+
/******************************************************************
* WCLINE_FillSimpleChar
*
@@ -382,11 +390,11 @@ static BOOL TERM_Init(void)
if (!getenv("TERM")) return FALSE;
if (TERM_bind_libcurses())
{
- if (setupterm(NULL, 1 /* really ?? */, NULL) == -1) return FALSE;
+ if (setupterm(NULL, WCLINE_output_fd, NULL) == -1) return FALSE;
TERM_init_done = TRUE;
TERM_BuildKeyDB();
/* set application key mode */
- tputs(tigetstr((char *)"smkx"), 1, putchar);
+ tputs(tigetstr((char *)"smkx"), 1, WCLINE_putchar);
}
return TRUE;
}
@@ -396,7 +404,7 @@ static BOOL TERM_Exit(void)
if (TERM_init_done)
{
/* put back the cursor key mode */
- tputs(tigetstr((char *)"rmkx"), 1, putchar);
+ tputs(tigetstr((char *)"rmkx"), 1, WCLINE_putchar);
}
return TRUE;
}
@@ -629,6 +637,8 @@ static int WCLINE_MainLoop(struct inner_data* data)
DWORD id;
struct termios term;
+ WCLINE_output_fd = data->output_fd;
+
if (!TERM_Init()) return 0;
WCLINE_Resize(data);
diff --git a/programs/wineconsole/winecon_private.h b/programs/wineconsole/winecon_private.h
index ff3fbd9..5884472 100644
--- a/programs/wineconsole/winecon_private.h
+++ b/programs/wineconsole/winecon_private.h
@@ -63,7 +63,7 @@ struct inner_data {
BOOL in_set_config; /* to handle re-entrant calls to WINECON_SetConfig */
BOOL in_grab_changes;/* to handle re-entrant calls to WINECON_GrabChanges */
BOOL dying; /* to TRUE when we've been notified by server that child has died */
-
+ int output_fd; /* when run in line mode, output fd to /dev/tty */
int (*fnMainLoop)(struct inner_data* data);
void (*fnPosCursor)(const struct inner_data* data);
void (*fnShapeCursor)(struct inner_data* data, int size, int vis, BOOL force);
diff --git a/programs/wineconsole/wineconsole.c b/programs/wineconsole/wineconsole.c
index ffd32c9..347c0b0 100644
--- a/programs/wineconsole/wineconsole.c
+++ b/programs/wineconsole/wineconsole.c
@@ -605,6 +605,10 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
/* should always be defined */
}
+ if (backend == WCLINE_InitBackend)
+ data->output_fd = isatty(1) ? 1 : open("/dev/tty", O_RDWR);
+ else
+ data->output_fd = -1;
/* the handles here are created without the whistles and bells required by console
* (mainly because wineconsole doesn't need it)
* - they are not inheritable
@@ -615,7 +619,6 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
req->access = GENERIC_READ | GENERIC_WRITE;
req->attributes = 0;
req->pid = pid;
- req->input_fd = -1;
ret = !wine_server_call_err( req );
data->hConIn = wine_server_ptr_handle( reply->handle_in );
@@ -625,13 +628,14 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
if (!ret) goto error;
WINE_TRACE("using hConIn %p, hSynchro event %p\n", data->hConIn, data->hSynchro);
+ if (data->output_fd != -1) wine_server_send_fd(data->output_fd);
SERVER_START_REQ(create_console_output)
{
req->handle_in = wine_server_obj_handle( data->hConIn );
req->access = GENERIC_WRITE|GENERIC_READ;
req->attributes = 0;
req->share = FILE_SHARE_READ|FILE_SHARE_WRITE;
- req->fd = -1;
+ req->fd = data->output_fd;
ret = !wine_server_call_err( req );
data->hConOut = wine_server_ptr_handle( reply->handle_out );
}
@@ -686,6 +690,18 @@ static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appna
return NULL;
}
+static inline HANDLE make_handle(int fd, HANDLE h, DWORD flg, DWORD sync)
+{
+ HANDLE ret = INVALID_HANDLE_VALUE;
+
+ if (isatty(fd))
+ DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(),
+ &ret, GENERIC_READ|GENERIC_WRITE|(sync ? SYNCHRONIZE : 0), TRUE, 0);
+ else
+ wine_server_fd_to_handle(fd, flg|SYNCHRONIZE, OBJ_INHERIT, &ret);
+ return ret;
+}
+
/******************************************************************
* WINECON_Spawn
*
@@ -702,15 +718,13 @@ static BOOL WINECON_Spawn(struct inner_data* data, LPWSTR cmdLine)
startup.cb = sizeof(startup);
startup.dwFlags = STARTF_USESTDHANDLES;
- /* the attributes of wineconsole's handles are not adequate for inheritance, so
- * get them with the correct attributes before process creation
+ /* we've been started from unix command line, so set up for child process either
+ * the newly allocated handles to this console instance, or file handles if
+ * input/output/error streams have been redirected from unix parent (a shell)
*/
- if (!DuplicateHandle(GetCurrentProcess(), data->hConIn, GetCurrentProcess(),
- &startup.hStdInput, GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE, TRUE, 0) ||
- !DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
- &startup.hStdOutput, GENERIC_READ|GENERIC_WRITE, TRUE, 0) ||
- !DuplicateHandle(GetCurrentProcess(), data->hConOut, GetCurrentProcess(),
- &startup.hStdError, GENERIC_READ|GENERIC_WRITE, TRUE, 0))
+ if ((startup.hStdInput = make_handle(0, data->hConIn, GENERIC_READ, TRUE)) == INVALID_HANDLE_VALUE ||
+ (startup.hStdOutput = make_handle(1, data->hConOut, GENERIC_WRITE, FALSE)) == INVALID_HANDLE_VALUE ||
+ (startup.hStdError = make_handle(2, data->hConOut, GENERIC_WRITE, FALSE)) == INVALID_HANDLE_VALUE)
{
WINE_ERR("Can't dup handles\n");
/* no need to delete handles, we're exiting the program anyway */
@@ -730,7 +744,8 @@ static BOOL WINECON_Spawn(struct inner_data* data, LPWSTR cmdLine)
return done;
}
-struct wc_init {
+struct wc_init
+{
LPCSTR ptr;
enum {from_event, from_process_name} mode;
enum init_return (*backend)(struct inner_data*);
diff --git a/server/console.c b/server/console.c
index 3f90937..03c93ca 100644
--- a/server/console.c
+++ b/server/console.c
@@ -62,12 +62,10 @@ struct console_input
int output_cp; /* console output codepage */
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 */
};
static void console_input_dump( struct object *obj, int verbose );
static void console_input_destroy( struct object *obj );
-static struct fd *console_input_get_fd( struct object *obj );
static const struct object_ops console_input_ops =
{
@@ -79,7 +77,7 @@ static const struct object_ops console_input_ops =
NULL, /* signaled */
no_satisfied, /* satisfied */
no_signal, /* signal */
- console_input_get_fd, /* get_fd */
+ no_get_fd, /* get_fd */
default_fd_map_access, /* map_access */
default_get_sd, /* get_sd */
default_set_sd, /* set_sd */
@@ -184,19 +182,9 @@ static struct list screen_buffer_list = LIST_INIT(screen_buffer_list);
static const char_info_t empty_char_info = { ' ', 0x000f }; /* white on black space */
-static int console_input_is_bare( struct console_input* cin )
-{
- return cin->evt == NULL;
-}
-
-static struct fd *console_input_get_fd( struct object* obj )
+static int console_output_is_bare( struct screen_buffer* sb )
{
- struct console_input *console_input = (struct console_input*)obj;
- assert( obj->ops == &console_input_ops );
- if (console_input->fd)
- return (struct fd*)grab_object( console_input->fd );
- set_error( STATUS_OBJECT_TYPE_MISMATCH );
- return NULL;
+ return sb->fd != NULL;
}
static enum server_fd_type console_get_fd_type( struct fd *fd )
@@ -236,7 +224,7 @@ static void console_input_events_append( struct console_input* console,
struct console_input_events* evts;
int collapsed = FALSE;
- if (!(evts = console->evt)) return;
+ evts = console->evt;
/* to be done even when evt has been generated by the renderer ? */
/* try to collapse evt into current queue's events */
@@ -295,7 +283,7 @@ static struct console_input_events *create_console_input_events(void)
return evt;
}
-static struct object *create_console_input( struct thread* renderer, int fd )
+static struct object *create_console_input( struct thread* renderer )
{
struct console_input *console_input;
@@ -308,7 +296,7 @@ static struct object *create_console_input( struct thread* renderer, int fd )
console_input->active = NULL;
console_input->recnum = 0;
console_input->records = NULL;
- console_input->evt = renderer ? create_console_input_events() : NULL;
+ console_input->evt = create_console_input_events();
console_input->title = NULL;
console_input->history_size = 50;
console_input->history = calloc( console_input->history_size, sizeof(WCHAR*) );
@@ -319,23 +307,12 @@ static struct object *create_console_input( struct thread* renderer, int fd )
console_input->output_cp = 0;
console_input->win = 0;
console_input->event = create_event( NULL, NULL, 0, 1, 0, NULL );
- console_input->fd = NULL;
- if (!console_input->history || (renderer && !console_input->evt) || !console_input->event)
+ if (!console_input->history || !console_input->evt || !console_input->event)
{
release_object( console_input );
return NULL;
}
- if (fd != -1) /* bare console */
- {
- if (!(console_input->fd = create_anonymous_fd( &console_fd_ops, fd, &console_input->obj,
- FILE_SYNCHRONOUS_IO_NONALERT )))
- {
- release_object( console_input );
- return NULL;
- }
- allow_fd_caching( console_input->fd );
- }
return &console_input->obj;
}
@@ -707,13 +684,6 @@ static int set_console_input_info( const struct set_console_input_info_request *
struct console_renderer_event evt;
if (!(console = console_input_get( req->handle, FILE_WRITE_PROPERTIES ))) goto error;
- if (console_input_is_bare(console) &&
- (req->mask & (SET_CONSOLE_INPUT_INFO_ACTIVE_SB|
- SET_CONSOLE_INPUT_INFO_WIN)))
- {
- set_error( STATUS_UNSUCCESSFUL );
- goto error;
- }
memset(&evt.u, 0, sizeof(evt.u));
if (req->mask & SET_CONSOLE_INPUT_INFO_ACTIVE_SB)
@@ -1098,14 +1068,9 @@ static void console_input_destroy( struct object *obj )
if (curr->input == console_in) curr->input = NULL;
}
- if (console_in->evt)
- {
- release_object( console_in->evt );
- console_in->evt = NULL;
- }
+ release_object( console_in->evt );
+ console_in->evt = NULL;
release_object( console_in->event );
- if (console_in->fd)
- release_object( console_in->fd );
for (i = 0; i < console_in->history_size; i++)
free( console_in->history[i] );
@@ -1384,7 +1349,6 @@ DECL_HANDLER(alloc_console)
struct process *process;
struct thread *renderer;
struct console_input *console;
- int fd;
int attach = 0;
switch (req->pid)
@@ -1400,13 +1364,6 @@ DECL_HANDLER(alloc_console)
grab_object( process );
attach = 1;
break;
- case 0xffffffff:
- /* no renderer, console to be attached to current process */
- renderer = NULL;
- process = current->process;
- grab_object( process );
- attach = 1;
- break;
default:
/* renderer is current, console to be attached to req->pid */
renderer = current;
@@ -1418,17 +1375,8 @@ DECL_HANDLER(alloc_console)
set_error( STATUS_ACCESS_DENIED );
goto the_end;
}
- if (req->input_fd != -1)
- {
- if ((fd = thread_get_inflight_fd( current, req->input_fd )) == -1)
- {
- set_error( STATUS_INVALID_PARAMETER );
- goto the_end;
- }
- }
- else fd = -1;
- if ((console = (struct console_input*)create_console_input( renderer, fd )))
+ if ((console = (struct console_input*)create_console_input( renderer )))
{
if ((in = alloc_handle( current->process, console, req->access, req->attributes )))
{
@@ -1607,7 +1555,8 @@ DECL_HANDLER(create_console_output)
close(fd);
return;
}
- if (console_input_is_bare( console ) ^ (fd != -1))
+ /* we only allow one screen buffer with link to stdout */
+ if (console->active != NULL && fd != -1)
{
close( fd );
release_object( console );
@@ -1672,7 +1621,7 @@ DECL_HANDLER(read_console_output)
if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
FILE_READ_DATA, &screen_buffer_ops )))
{
- if (console_input_is_bare( screen_buffer->input ))
+ if (console_output_is_bare( screen_buffer ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
release_object( screen_buffer );
@@ -1693,7 +1642,7 @@ DECL_HANDLER(write_console_output)
if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
FILE_WRITE_DATA, &screen_buffer_ops)))
{
- if (console_input_is_bare( screen_buffer->input ))
+ if (console_output_is_bare( screen_buffer ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
release_object( screen_buffer );
@@ -1715,7 +1664,7 @@ DECL_HANDLER(fill_console_output)
if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
FILE_WRITE_DATA, &screen_buffer_ops)))
{
- if (console_input_is_bare( screen_buffer->input ))
+ if (console_output_is_bare( screen_buffer ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
release_object( screen_buffer );
@@ -1735,7 +1684,7 @@ DECL_HANDLER(move_console_output)
if ((screen_buffer = (struct screen_buffer*)get_handle_obj( current->process, req->handle,
FILE_WRITE_DATA, &screen_buffer_ops)))
{
- if (console_input_is_bare( screen_buffer->input ))
+ if (console_output_is_bare( screen_buffer ))
{
set_error( STATUS_OBJECT_TYPE_MISMATCH );
release_object( screen_buffer );
diff --git a/server/protocol.def b/server/protocol.def
index 886853f..612a451 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1198,7 +1198,6 @@ enum server_fd_type
unsigned int access; /* wanted access rights */
unsigned int attributes; /* object attributes */
process_id_t pid; /* pid of process which shall be attached to the console */
- int input_fd; /* if pid=-1 (bare console to current process), fd for input */
@REPLY
obj_handle_t handle_in; /* handle to console input */
obj_handle_t event; /* handle to renderer events change notification */
diff --git a/server/request.h b/server/request.h
index f566e0d..90493ca 100644
--- a/server/request.h
+++ b/server/request.h
@@ -967,8 +967,7 @@ C_ASSERT( sizeof(struct set_socket_deferred_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, access) == 12 );
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, attributes) == 16 );
C_ASSERT( FIELD_OFFSET(struct alloc_console_request, pid) == 20 );
-C_ASSERT( FIELD_OFFSET(struct alloc_console_request, input_fd) == 24 );
-C_ASSERT( sizeof(struct alloc_console_request) == 32 );
+C_ASSERT( sizeof(struct alloc_console_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, handle_in) == 8 );
C_ASSERT( FIELD_OFFSET(struct alloc_console_reply, event) == 12 );
C_ASSERT( sizeof(struct alloc_console_reply) == 16 );
diff --git a/server/trace.c b/server/trace.c
index dc5074f..219176f 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1626,7 +1626,6 @@ static void dump_alloc_console_request( const struct alloc_console_request *req
fprintf( stderr, " access=%08x", req->access );
fprintf( stderr, ", attributes=%08x", req->attributes );
fprintf( stderr, ", pid=%04x", req->pid );
- fprintf( stderr, ", input_fd=%d", req->input_fd );
}
static void dump_alloc_console_reply( const struct alloc_console_reply *req )
More information about the wine-patches
mailing list