[PATCH 4/5] Force using wineconsole as input manager for the bare consoles

Eric Pouech eric.pouech at orange.fr
Sat Dec 15 02:22:43 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            |  306 +++---------------------------------
 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/wineconsole.c |   42 +++--
 server/console.c                   |   83 ++--------
 server/protocol.def                |    1 
 server/request.h                   |    3 
 server/trace.c                     |    1 
 12 files changed, 99 insertions(+), 376 deletions(-)


diff --git a/dlls/kernel32/console.c b/dlls/kernel32/console.c
index d6d1414..c7958cb 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,8 @@ 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
+         * to do the job)
          */
         len = WideCharToMultiByte(CP_UNIXCP, 0, lpBuffer, nNumberOfCharsToWrite, NULL, 0, NULL, NULL);
         if ((ptr = HeapAlloc(GetProcessHeap(), 0, len)) == NULL)
@@ -3052,64 +2857,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 +2864,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 +2879,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..9669055 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;
@@ -922,6 +922,7 @@ WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, BOOL can_pos_cursor)
     void		(*func)(struct WCEL_Context* ctx);
     DWORD               mode, ks;
     int                 use_emacs;
+    BOOL                can_pos_cursor;
 
     memset(&ctx, 0, sizeof(ctx));
     ctx.hConIn = hConsoleIn;
@@ -935,6 +936,7 @@ WCHAR* CONSOLE_Readline(HANDLE hConsoleIn, BOOL can_pos_cursor)
 	!GetConsoleScreenBufferInfo(ctx.hConOut, &ctx.csbi))
 	return NULL;
     if (!GetConsoleMode(hConsoleIn, &mode)) mode = 0;
+    can_pos_cursor = !CONSOLE_is_handle_line_mode(ctx.hConOut);
     ctx.shall_echo = (mode & ENABLE_ECHO_INPUT) ? 1 : 0;
     ctx.insert = (mode & (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS)) == (ENABLE_INSERT_MODE|ENABLE_EXTENDED_FLAGS) ? 1 : 0;
     if (!GetConsoleMode(ctx.hConOut, &mode)) mode = 0;
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( &params->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/wineconsole.c b/programs/wineconsole/wineconsole.c
index ffd32c9..9c8c5af 100644
--- a/programs/wineconsole/wineconsole.c
+++ b/programs/wineconsole/wineconsole.c
@@ -570,7 +570,7 @@ static BOOL WINECON_GetServerConfig(struct inner_data* data)
  */
 static struct inner_data* WINECON_Init(HINSTANCE hInst, DWORD pid, LPCWSTR appname,
                                        enum init_return (*backend)(struct inner_data*),
-                                       INT nCmdShow)
+                                       int fd, INT nCmdShow)
 {
     struct inner_data*	data = NULL;
     DWORD		ret;
@@ -615,7 +615,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 +624,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 (fd != -1) wine_server_send_fd(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         = fd;
         ret = !wine_server_call_err( req );
         data->hConOut   = wine_server_ptr_handle( reply->handle_out );
     }
@@ -686,6 +686,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 +714,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,11 +740,13 @@ 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*);
     HANDLE              event;
+    int                 fd;
 };
 
 #define WINECON_CMD_SHOW_USAGE 0x10000
@@ -752,6 +764,7 @@ static UINT WINECON_ParseOptions(const char* lpCmdLine, struct wc_init* wci)
     wci->ptr = lpCmdLine;
     wci->mode = from_process_name;
     wci->backend = WCUSER_InitBackend;
+    wci->fd = -1;
 
     for (;;)
     {
@@ -780,6 +793,7 @@ static UINT WINECON_ParseOptions(const char* lpCmdLine, struct wc_init* wci)
             else if (strncmp(wci->ptr + 10, "line", 4) == 0)
             {
                 wci->backend = WCLINE_InitBackend;
+                wci->fd = 1;
                 wci->ptr += 14;
             }
             else
@@ -826,7 +840,7 @@ int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, INT nCmdSh
     {
     case from_event:
         /* case of wineconsole <evt>, signal process that created us that we're up and running */
-        if (!(data = WINECON_Init(hInst, 0, NULL, wci.backend, nCmdShow))) return 0;
+        if (!(data = WINECON_Init(hInst, 0, NULL, wci.backend, wci.fd, nCmdShow))) return 0;
 	ret = SetEvent(wci.event);
 	if (!ret) WINE_ERR("SetEvent failed.\n");
         break;
@@ -836,7 +850,7 @@ int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmdLine, INT nCmdSh
 
             MultiByteToWideChar(CP_ACP, 0, wci.ptr, -1, buffer, sizeof(buffer) / sizeof(buffer[0]));
 
-            if (!(data = WINECON_Init(hInst, GetCurrentProcessId(), buffer, wci.backend, nCmdShow)))
+            if (!(data = WINECON_Init(hInst, GetCurrentProcessId(), buffer, wci.backend, wci.fd, nCmdShow)))
                 return 0;
             ret = WINECON_Spawn(data, buffer);
             if (!ret)
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