From fdf568aaaef658de63f94d8f58feb872105f5c7c Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Wed, 5 May 2021 20:39:00 +0200 Subject: [PATCH] ntdll: Inherit tty std input and output in processes attached to Unix console. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50117 Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/ntdll/unix/process.c | 53 +++++++++++++++++++++++++++----------- include/wine/condrv.h | 1 + programs/conhost/conhost.c | 6 +++++ 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c index ce2033bc0dc..79a4bbce7a8 100644 --- a/dlls/ntdll/unix/process.c +++ b/dlls/ntdll/unix/process.c @@ -58,7 +58,9 @@ #define WIN32_NO_STATUS #include "windef.h" #include "winternl.h" +#include "winioctl.h" #include "unix_private.h" +#include "wine/condrv.h" #include "wine/exception.h" #include "wine/server.h" #include "wine/debug.h" @@ -387,12 +389,23 @@ static void set_stdio_fd( int stdin_fd, int stdout_fd ) if (stdout_fd == -1) stdout_fd = fd; } - dup2( stdin_fd, 0 ); - dup2( stdout_fd, 1 ); + if (stdin_fd != 0) dup2( stdin_fd, 0 ); + if (stdout_fd != 1) dup2( stdout_fd, 1 ); if (fd != -1) close( fd ); } +/*********************************************************************** + * is_unix_console_handle + */ +static BOOL is_unix_console_handle( HANDLE handle ) +{ + IO_STATUS_BLOCK io; + return !NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io, IOCTL_CONDRV_IS_UNIX, + NULL, 0, NULL, 0 ); +} + + /*********************************************************************** * spawn_process */ @@ -404,8 +417,13 @@ static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int so pid_t pid; char **argv; - wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ); - wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ); + if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) && + isatty(0) && is_unix_console_handle( params->hStdInput )) + stdin_fd = 0; + + if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) && + isatty(1) && is_unix_console_handle( params->hStdOutput )) + stdout_fd = 1; if (!(pid = fork())) /* child */ { @@ -420,8 +438,8 @@ static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int so } else set_stdio_fd( stdin_fd, stdout_fd ); - if (stdin_fd != -1) close( stdin_fd ); - if (stdout_fd != -1) close( stdout_fd ); + if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd ); + if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd ); if (winedebug) putenv( winedebug ); if (unixdir != -1) @@ -448,8 +466,8 @@ static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int so } else status = STATUS_NO_MEMORY; - if (stdin_fd != -1) close( stdin_fd ); - if (stdout_fd != -1) close( stdout_fd ); + if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd ); + if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd ); return status; } @@ -484,8 +502,13 @@ static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir, fcntl( fd[1], F_SETFD, FD_CLOEXEC ); } - wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ); - wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ); + if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) && + isatty(0) && is_unix_console_handle( params->hStdInput )) + stdin_fd = 0; + + if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) && + isatty(1) && is_unix_console_handle( params->hStdOutput )) + stdout_fd = 1; if (!(pid = fork())) /* child */ { @@ -494,7 +517,7 @@ static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir, close( fd[0] ); if (params->ConsoleFlags || - params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ || + params->ConsoleHandle == CONSOLE_HANDLE_ALLOC || (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE)) { setsid(); @@ -502,8 +525,8 @@ static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir, } else set_stdio_fd( stdin_fd, stdout_fd ); - if (stdin_fd != -1) close( stdin_fd ); - if (stdout_fd != -1) close( stdout_fd ); + if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd ); + if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd ); /* Reset signals that we previously set to SIG_IGN */ signal( SIGPIPE, SIG_DFL ); @@ -550,8 +573,8 @@ static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir, else status = STATUS_NO_MEMORY; close( fd[0] ); - if (stdin_fd != -1) close( stdin_fd ); - if (stdout_fd != -1) close( stdout_fd ); + if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd ); + if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd ); done: free( unix_name ); return status; diff --git a/include/wine/condrv.h b/include/wine/condrv.h index 5c3c550070d..add08be20c8 100644 --- a/include/wine/condrv.h +++ b/include/wine/condrv.h @@ -27,6 +27,7 @@ /* common console input and output ioctls */ #define IOCTL_CONDRV_GET_MODE CTL_CODE(FILE_DEVICE_CONSOLE, 0, METHOD_BUFFERED, FILE_READ_ACCESS) #define IOCTL_CONDRV_SET_MODE CTL_CODE(FILE_DEVICE_CONSOLE, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define IOCTL_CONDRV_IS_UNIX CTL_CODE(FILE_DEVICE_CONSOLE, 2, METHOD_BUFFERED, FILE_ANY_ACCESS) /* console input ioctls */ #define IOCTL_CONDRV_READ_CONSOLE CTL_CODE(FILE_DEVICE_CONSOLE, 10, METHOD_BUFFERED, FILE_READ_ACCESS) diff --git a/programs/conhost/conhost.c b/programs/conhost/conhost.c index f83528cb5f6..dd423ee5491 100644 --- a/programs/conhost/conhost.c +++ b/programs/conhost/conhost.c @@ -2375,6 +2375,9 @@ static NTSTATUS screen_buffer_ioctl( struct screen_buffer *screen_buffer, unsign TRACE( "set %x mode\n", screen_buffer->mode ); return STATUS_SUCCESS; + case IOCTL_CONDRV_IS_UNIX: + return screen_buffer->console->is_unix ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED; + case IOCTL_CONDRV_WRITE_CONSOLE: if (in_size % sizeof(WCHAR) || *out_size) return STATUS_INVALID_PARAMETER; return write_console( screen_buffer, in_data, in_size / sizeof(WCHAR) ); @@ -2452,6 +2455,9 @@ static NTSTATUS console_input_ioctl( struct console *console, unsigned int code, TRACE( "set %x mode\n", console->mode ); return STATUS_SUCCESS; + case IOCTL_CONDRV_IS_UNIX: + return console->is_unix ? STATUS_SUCCESS : STATUS_NOT_SUPPORTED; + case IOCTL_CONDRV_READ_CONSOLE: if (in_size || *out_size % sizeof(WCHAR)) return STATUS_INVALID_PARAMETER; ensure_tty_input_thread( console );