IDEA-333736: Fix tty size for WSL

The problem:
https://github.com/microsoft/WSL/issues/10701

When stdout/err are redirected, WSL reports tty size as 1x1 which breaks `ps` tool (famous "expect trouble" message) that some people might have in profile.

`ttyfix` explicitly sets tty size and inserted by `WslDistribution`.

Tiny refactoring moved `getToolPath` to reuse it


Merge-request: KT-MR-12821
Merged-by: Ilya Kazakevich <ilya.kazakevich@jetbrains.com>

GitOrigin-RevId: f33a906b139d22ecdaf0f1b0616ecaaf7bebdd16
This commit is contained in:
Ilya.Kazakevich
2023-11-03 15:35:26 +00:00
committed by intellij-monorepo-bot
parent de204fe198
commit 44be55aeee
11 changed files with 86 additions and 20 deletions

BIN
bin/win/aarch64/ttyfix Normal file

Binary file not shown.

BIN
bin/win/amd64/ttyfix Normal file

Binary file not shown.

View File

@@ -10,7 +10,7 @@ CFLAGS = -Wall -Wextra -pedantic -Werror -Os -D_POSIX_SOURCE=1 -D_BSD_SOURCE=1
LDFLAGS = -static
CC = $(MUSL_CC)
all: $(MUSL_CC) wslproxy wslhash
all: $(MUSL_CC) wslproxy wslhash ttyfix
$(MUSL_DISTR):
@echo I will now download musl. If it fails, check you have wget and see README
@@ -21,9 +21,10 @@ $(MUSL_CC): $(MUSL_DISTR)
cd $(MUSL_DISTR) && ./configure --prefix=$(MUSL_HOME) --syslibdir=$(MUSL_HOME)/lib && $(MAKE) && $(MAKE) install
wslproxy: wslproxy.c | $(MUSL_CC)
ttyfix: ttyfix.c | $(MUSL_CC)
wslhash: wslhash.c xxhash.h xxhash.c | $(MUSL_CC)
.PHONY: all clean
clean:
$(RM) wslproxy wslhash
$(RM) wslproxy wslhash ttyfix

View File

@@ -17,4 +17,4 @@ $(MUSL_CROSS_DISTR):
.PHONY: all clean
clean:
$(RM) wslproxy wslhash
$(RM) wslproxy wslhash ttyfix

View File

@@ -1,4 +1,4 @@
This project creates two tools:
This project creates three tools:
wslproxy (see wslproxy.svg)
To avoid connecting from WSL to Windows (such connections may be blocked by firewall) we connect from Windows to WSL instead.
@@ -12,6 +12,9 @@ and also it may be slow: access from WSL to Windows takes a lot of time.
This tool runs on WSL only, so it is fast. See WslSync.kt
It also reports symbolic links
ttyfix
Sets tty size to workaround https://github.com/microsoft/WSL/issues/10701
To build tool use Makefile. We link it statically because WSL may lack glibc. Kernel ABI is backward compatible, so use some old Linux
We use musl libc: https://musl.libc.org/

29
native/WslTools/ttyfix.c Normal file
View File

@@ -0,0 +1,29 @@
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
// Workaround for https://github.com/microsoft/WSL/issues/10701
// Provide command to execute along with args. Command will see 100x100 terminal
int main(int argc, char *argv[], char *envp[]) {
if (argc < 2) {
fprintf(stderr, "No command provided");
return -1;
}
struct winsize w;
int fd = open(ctermid(NULL), O_RDWR);
if (fd != -1) { //No terminal, ignore
const int size_ok = (ioctl(fd, TIOCGWINSZ, &w) == 0 && w.ws_col > 10 && w.ws_row > 10);
if (!size_ok) {
w.ws_col = 100;
w.ws_row = 100;
ioctl(fd, TIOCSWINSZ, &w); // Set window size
}
close(fd);
}
return execve(argv[1], argv + 1, envp); // Substitute self with provided command
}

View File

@@ -3,6 +3,7 @@ package com.intellij.execution.wsl
import com.intellij.execution.ExecutionException
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.openapi.application.PathManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.NlsSafe
import org.jetbrains.annotations.ApiStatus
@@ -57,4 +58,16 @@ interface AbstractWslDistribution {
@get:NlsSafe
val msId: String
}
}
/**
* throws exception instead of null
*/
fun AbstractWslDistribution.getWslPathSafe(path: Path): String =
getWslPath(path) ?: throw Exception("Can't access from Linux: $path")
/**
* How Linux can access tool from IJ "bin" folder
*/
fun AbstractWslDistribution.getToolLinuxPath(toolName: String): String =
getWslPathSafe(PathManager.findBinFileWithException(toolName))

View File

@@ -334,10 +334,13 @@ public class WSLDistribution implements AbstractWslDistribution {
}
if (options.isExecuteCommandInDefaultShell()) {
fixTTYSize(commandLine);
commandLine.addParameters(SHELL_PARAMETER, "-c", linuxCommandStr);
}
else {
commandLine.addParameters(EXEC_PARAMETER, getShellPath());
commandLine.addParameter(EXEC_PARAMETER);
fixTTYSize(commandLine);
commandLine.addParameter(getShellPath());
if (options.isExecuteCommandInInteractiveShell()) {
commandLine.addParameters("-i");
}
@@ -368,6 +371,20 @@ public class WSLDistribution implements AbstractWslDistribution {
return commandLine;
}
/**
* Workaround for <a href="https://github.com/microsoft/WSL/issues/10701">wrong tty size WSL problem</a>
*/
private void fixTTYSize(@NotNull GeneralCommandLine cmd) {
if (!WslDistributionDescriptor.isCalculatingMountRootCommand(cmd)
// Even though mount root is calculated with `options.isExecuteCommandInShell()=false`,
// let's protect from possible infinite recursion.
&& !(cmd instanceof PtyCommandLine) // PTY command line has correct tty size
&& Registry.is("wsl.fix.initial.tty.size.when.running.without.tty", true)) {
var ttyfix = AbstractWslDistributionKt.getToolLinuxPath(this, "ttyfix");
cmd.addParameter(ttyfix);
}
}
private void logCommandLineBefore(@NotNull GeneralCommandLine commandLine, @NotNull WSLCommandLineOptions options) {
if (LOG.isTraceEnabled()) {
LOG.trace("[" + getId() + "] " +

View File

@@ -12,6 +12,7 @@ import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.util.ClearableLazyValue;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsSafe;
import com.intellij.openapi.util.io.OSAgnosticPathUtil;
import com.intellij.openapi.util.text.StringUtil;
@@ -37,6 +38,8 @@ import static com.intellij.execution.wsl.WSLUtil.LOG;
final class WslDistributionDescriptor {
private static final int PROBE_TIMEOUT = SystemProperties.getIntProperty("ide.wsl.probe.timeout", 60_000);
private static final Key<Boolean> CALCULATING_MOUNT_ROOT_COMMAND = new Key<>("CalculatingMountRootCommand");
@Tag("id")
private @NlsSafe String myId;
@Tag("microsoft-id")
@@ -145,6 +148,8 @@ final class WslDistributionDescriptor {
WSLCommandLineOptions options = new WSLCommandLineOptions().setLaunchWithWslExe(true).setExecuteCommandInShell(false);
GeneralCommandLine commandLine = new GeneralCommandLine("pwd");
// Required to prevent recursion
commandLine.putUserData(CALCULATING_MOUNT_ROOT_COMMAND, true);
// Use interoperability between Windows and Linux - the Linux process inherits the Windows working directory.
commandLine.setWorkDirectory(windowsWorkingDirectory);
String linuxWorkingDirectory = readWslOutputLine(options, commandLine, pi);
@@ -208,6 +213,14 @@ final class WslDistributionDescriptor {
return output.getStdoutLines();
}
/**
* Command line is used to calculate mount root
*/
static boolean isCalculatingMountRootCommand(@NotNull GeneralCommandLine commandLine) {
Boolean data = commandLine.getUserData(CALCULATING_MOUNT_ROOT_COMMAND);
return data != null && data;
}
private static <T> T executeOrRunTask(@NotNull Function<? super @Nullable ProgressIndicator, ? extends T> commandRunner) {
if (!ApplicationManager.getApplication().isDispatchThread()) {
return commandRunner.apply(null);

View File

@@ -158,6 +158,10 @@
description="Use 'wsl.exe -l -v' to get distribution list. If it's disabled 'wsl.exe -l -q' will be used."/>
<registryKey key="wsl.use.utf8.encoding" os="windows" defaultValue="true" restartRequired="false"
description="Use UTF-8 as default encoding for all WSL distributions, otherwise default console encoding will be used (see Preferences | Editor | General | Console )"/>
<registryKey key="wsl.fix.initial.tty.size.when.running.without.tty"
restartRequired="false"
description="Set initial Linux tty size to 100x100 for WSL processes not attached to Windows PTY (workaround for https://github.com/microsoft/WSL/issues/10701)"
defaultValue="true"/>
<applicationService serviceInterface="com.intellij.execution.wsl.WslDistributionManager"
serviceImplementation="com.intellij.execution.wsl.WslDistributionManagerImpl"/>
<executionTargetType implementation="com.intellij.execution.wsl.target.WslTargetType"/>

View File

@@ -2,20 +2,6 @@ package com.intellij.execution.wsl
import com.intellij.execution.configurations.GeneralCommandLine
import com.intellij.execution.processTools.ProcessExistedNotZeroException
import com.intellij.openapi.application.PathManager
import java.nio.file.Path
/**
* throws exception instead of null
*/
internal fun AbstractWslDistribution.getWslPathSafe(path: Path): String = getWslPath(path)
?: throw Exception("Can't access from Linux: $path")
/**
* How Linux can access tool from IJ "bin" folder
*/
internal fun AbstractWslDistribution.getToolLinuxPath(toolName: String): String =
getWslPathSafe(PathManager.findBinFileWithException(toolName))
internal fun AbstractWslDistribution.getTool(toolName: String, vararg arguments: String): GeneralCommandLine {
val toolOnLinux = getToolLinuxPath(toolName)