From dff54fd8533555c8db5ca71055160cad69ba31e2 Mon Sep 17 00:00:00 2001 From: "K.G. Wang" Date: Sun, 21 Jul 2024 02:25:22 +0800 Subject: [PATCH] [os] detect shell charset --- .../src/main/java/io/vproxy/base/util/OS.java | 73 +++++++++++++++++++ .../main/java/io/vproxy/base/util/Utils.java | 11 ++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/base/src/main/java/io/vproxy/base/util/OS.java b/base/src/main/java/io/vproxy/base/util/OS.java index d027a84d..e0a3398b 100644 --- a/base/src/main/java/io/vproxy/base/util/OS.java +++ b/base/src/main/java/io/vproxy/base/util/OS.java @@ -1,5 +1,10 @@ package io.vproxy.base.util; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + public class OS { private static final String osname; private static final String osversion; @@ -79,4 +84,72 @@ public static boolean isLinux() { public static String arch() { return arch; } + + private static Charset SHELL_CHARSET = null; + + public static Charset shellCharset() { + if (SHELL_CHARSET != null) { + return SHELL_CHARSET; + } + var charsets = new ArrayList(); + charsets.add(StandardCharsets.UTF_8); + try { + charsets.add(Charset.forName("GBK")); + } catch (Throwable ignore) { + } + //noinspection UnnecessaryUnicodeEscape + var testStr = "\u4F60\u597D\uFF0C\u4E16\u754C"; // 你好,世界 + String cmd; + if (isWindows()) { + cmd = "echo " + testStr; + } else { + cmd = "echo \"" + testStr + "\""; + } + for (var c : charsets) { + var s = new String(cmd.getBytes(c), c); + ProcessBuilder pb; + if (isWindows()) { + pb = new ProcessBuilder("cmd.exe", "/c", s); + } else { + pb = new ProcessBuilder("/bin/sh", "-c", s); + } + int exitCode; + String stdout; + String stderr; + try { + var p = pb.start(); + var ok = p.waitFor(500, TimeUnit.MILLISECONDS); + if (!ok) { + Logger.warn(LogType.SYS_ERROR, "failed executing cmd: " + cmd + ", command didn't finish in 500ms"); + try { + p.destroyForcibly(); + } catch (Throwable ignore) { + } + continue; + } + exitCode = p.exitValue(); + stdout = new String(p.getInputStream().readAllBytes(), c); + stderr = new String(p.getErrorStream().readAllBytes(), c); + } catch (Exception e) { + Logger.warn(LogType.SYS_ERROR, "failed executing cmd: " + cmd, e); + continue; + } + if (exitCode != 0) { + Logger.warn(LogType.SYS_ERROR, "failed executing cmd: " + cmd + ", exitCode = " + exitCode + + ", stdout = " + stdout + ", stderr = " + stderr); + continue; + } + stdout = stdout.trim(); + if (testStr.equals(stdout)) { + Logger.alert("shell charset is determined: " + c + ", getting result: " + stdout); + SHELL_CHARSET = c; + return c; + } else { + Logger.warn(LogType.ALERT, "shell charset is not " + c + ", getting result: `" + stdout + "`"); + } + } + Logger.warn(LogType.ALERT, "shell charset cannot be determined, using UTF-8 by default"); + SHELL_CHARSET = StandardCharsets.UTF_8; + return SHELL_CHARSET; + } } diff --git a/base/src/main/java/io/vproxy/base/util/Utils.java b/base/src/main/java/io/vproxy/base/util/Utils.java index 4d000d27..3c0084db 100644 --- a/base/src/main/java/io/vproxy/base/util/Utils.java +++ b/base/src/main/java/io/vproxy/base/util/Utils.java @@ -599,15 +599,18 @@ public static ExecuteResult execute(String script, int timeout, boolean getResul } File file = File.createTempFile("script", OS.isWindows() ? ".bat" : ".sh"); try { - Files.writeString(file.toPath(), script); + script = "@echo off\r\n" + script; + Files.writeString(file.toPath(), script, OS.shellCharset()); if (!file.setExecutable(true)) { - throw new Exception("setting executable to script " + file.getAbsolutePath() + " failed"); + throw new Exception("chmod +x " + file.getAbsolutePath() + " failed"); } + var filePath = file.getAbsolutePath(); + filePath = new String(filePath.getBytes(OS.shellCharset()), OS.shellCharset()); ProcessBuilder pb; if (OS.isWindows()) { - pb = new ProcessBuilder("cmd.exe", "/c", file.getAbsolutePath()); + pb = new ProcessBuilder("cmd.exe", "/c", filePath); } else { - pb = new ProcessBuilder(file.getAbsolutePath()); + pb = new ProcessBuilder(filePath); } return execute(pb, timeout, getResult); } finally {