diff --git a/client/hostinfo_win.cpp b/client/hostinfo_win.cpp
index ab75d174f7e..e17f8b9ed80 100644
--- a/client/hostinfo_win.cpp
+++ b/client/hostinfo_win.cpp
@@ -1669,9 +1669,14 @@ int HOST_INFO::get_host_info(bool init) {
if (!cc_config.dont_use_wsl) {
OSVERSIONINFOEX osvi;
if (get_OSVERSIONINFO(osvi) && osvi.dwMajorVersion >= 10) {
- get_wsl_information(
+ retval = get_wsl_information(
cc_config.allowed_wsls, wsl_distros, !cc_config.dont_use_docker
);
+ if (retval) {
+ msg_printf(0, MSG_INTERNAL_ERROR,
+ "get_wsl_information(): %s", boincerror(retval)
+ );
+ }
}
}
#endif
diff --git a/client/hostinfo_wsl.cpp b/client/hostinfo_wsl.cpp
index 096d5ea765b..4683606cc15 100644
--- a/client/hostinfo_wsl.cpp
+++ b/client/hostinfo_wsl.cpp
@@ -15,20 +15,18 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see .
-#ifdef _WIN64
-
using std::vector;
using std::string;
#include "boinc_win.h"
+#include "win_util.h"
#include "str_replace.h"
#include "client_msgs.h"
#include "hostinfo.h"
-// scan the registry to get the list of all distros on this host.
+// scan the registry to get the list of all WSL distros on this host.
// See https://patrickwu.space/2020/07/19/wsl-related-registry/
-// Return nonzero on error
//
int get_all_distros(WSL_DISTROS& distros) {
const std::string lxss_path = "Software\\Microsoft\\Windows\\CurrentVersion\\Lxss";
@@ -117,145 +115,6 @@ int get_all_distros(WSL_DISTROS& distros) {
return 0;
}
-// we run WSL commands by calling a DLL function,
-// and communicating with it through two pipes
-
-typedef HRESULT(WINAPI *PWslLaunch)(PCWSTR, PCWSTR, BOOL, HANDLE, HANDLE, HANDLE, HANDLE*);
-
-// handles for running a WSL command
-//
-struct WSL_CMD {
- HINSTANCE wsl_lib = NULL;
- HANDLE in_read = NULL;
- HANDLE in_write = NULL;
- HANDLE out_read = NULL;
- HANDLE out_write = NULL;
- PWslLaunch pWslLaunch = NULL;
-
- ~WSL_CMD() {
- close_handle(in_read);
- close_handle(in_write);
- close_handle(out_read);
- close_handle(out_write);
-
- if (wsl_lib) {
- FreeLibrary(wsl_lib);
- }
- }
-
- int prepare_cmd() {
- wsl_lib = NULL;
- in_read = NULL;
- in_write = NULL;
- out_read = NULL;
- out_write = NULL;
- pWslLaunch = NULL;
-
- wsl_lib = LoadLibrary("wslapi.dll");
- if (!wsl_lib) {
- return 1;
- }
-
- pWslLaunch = (PWslLaunch)GetProcAddress(wsl_lib, "WslLaunch");
-
- if (!pWslLaunch) {
- return 1;
- }
-
- SECURITY_ATTRIBUTES sa;
- sa.nLength = sizeof(SECURITY_ATTRIBUTES);
- sa.bInheritHandle = TRUE;
- sa.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe(&out_read, &out_write, &sa, 0)) {
- return 1;
- }
- if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) {
- return 1;
- }
- if (!CreatePipe(&in_read, &in_write, &sa, 0)) {
- return 1;
- }
- if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) {
- return 1;
- }
-
- return 0;
- }
-
-private:
- inline void close_handle(HANDLE handle) {
- if (handle) {
- CloseHandle(handle);
- }
- }
-};
-
-// convert std::string to PCWSTR
-// taken from https://stackoverflow.com/questions/27220/how-to-convert-stdstring-to-lpcwstr-in-c-unicode
-//
-std::wstring s2ws(const std::string& s) {
- const int slength = (int)s.length() + 1;
- const int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0);
- wchar_t* buf = new wchar_t[len];
- MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
- std::wstring r(buf);
- delete[] buf;
- return r;
-}
-
-// run a (Linux) command in the given distro,
-// using the given pipes.
-// Return S_OK on success
-//
-bool create_wsl_process(
- const WSL_CMD& rs, const std::string& wsl_distro_name,
- const std::string& command, HANDLE* handle,
- bool use_current_work_dir = false
-) {
- HRESULT ret = rs.pWslLaunch(
- s2ws(wsl_distro_name).c_str(), s2ws(command).c_str(),
- use_current_work_dir, rs.in_read, rs.out_write, rs.out_write,
- handle
- );
- return (ret == S_OK);
-}
-
-#if 0
-bool CreateWslProcess(
- const HANDLE& out_write, const std::string& wsl_app,
- const std::string& command, HANDLE& handle
-) {
- PROCESS_INFORMATION pi;
- STARTUPINFO si;
-
- ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
- ZeroMemory(&si, sizeof(STARTUPINFO));
-
- si.cb = sizeof(STARTUPINFO);
- si.hStdError = out_write;
- si.hStdOutput = out_write;
- si.hStdInput = NULL;
- si.dwFlags |= STARTF_USESTDHANDLES;
-
- const DWORD dwFlags = CREATE_NO_WINDOW;
-
- const std::string cmd = wsl_app + " " + command;
-
- const bool res = (CreateProcess(
- NULL, (LPSTR)cmd.c_str(), NULL, NULL, TRUE, dwFlags,
- NULL, NULL, &si, &pi
- ) != FALSE);
-
- if (res) {
- handle = pi.hProcess;
- CloseHandle(pi.hThread);
- }
-
- return res;
-}
-#endif
-
// read from the given pipe until the given process exits;
// return the result
//
@@ -314,7 +173,9 @@ void parse_sysctl_output(
// if either name or version is not already there, add
//
-static void update_os(WSL_DISTRO &wd, const char* os_name, const char* os_version) {
+static void update_os(
+ WSL_DISTRO &wd, const char* os_name, const char* os_version
+) {
if (wd.os_name.empty() && strlen(os_name)) {
wd.os_name = os_name;
}
@@ -323,7 +184,7 @@ static void update_os(WSL_DISTRO &wd, const char* os_name, const char* os_versio
}
}
-// have both name and version?
+// have both OS name and version?
//
static bool got_both(WSL_DISTRO &wd) {
return !wd.os_name.empty() && !wd.os_version.empty();
@@ -346,7 +207,7 @@ int get_wsl_information(
WSL_CMD rs;
- if (rs.prepare_cmd()) {
+ if (rs.setup()) {
return -1;
}
@@ -378,48 +239,51 @@ int get_wsl_information(
// try running 'lsbrelease -a'
//
- if (!create_wsl_process(rs, wd.distro_name, command_lsbrelease, &proc_handle)) {
- continue;
+ if (!rs.run_command(
+ wd.distro_name, command_lsbrelease, &proc_handle
+ )) {
+ HOST_INFO::parse_linux_os_info(
+ read_from_pipe(proc_handle, rs.out_read), lsbrelease,
+ os_name, sizeof(os_name),
+ os_version, sizeof(os_version)
+ );
+ CloseHandle(proc_handle);
+ update_os(wd, os_name, os_version);
}
- HOST_INFO::parse_linux_os_info(
- read_from_pipe(proc_handle, rs.out_read), lsbrelease,
- os_name, sizeof(os_name),
- os_version, sizeof(os_version)
- );
- CloseHandle(proc_handle);
- update_os(wd, os_name, os_version);
// try reading '/etc/os-relese'
//
if (!got_both(wd)) {
const std::string command_osrelease = "cat " + std::string(file_osrelease);
- if (!create_wsl_process(rs, wd.distro_name, command_osrelease, &proc_handle)) {
- continue;
+ if (!rs.run_command(
+ wd.distro_name, command_osrelease, &proc_handle
+ )) {
+ HOST_INFO::parse_linux_os_info(
+ read_from_pipe(proc_handle, rs.out_read),
+ osrelease,
+ os_name, sizeof(os_name),
+ os_version, sizeof(os_version)
+ );
+ CloseHandle(proc_handle);
+ update_os(wd, os_name, os_version);
}
- HOST_INFO::parse_linux_os_info(
- read_from_pipe(proc_handle, rs.out_read),
- osrelease,
- os_name, sizeof(os_name),
- os_version, sizeof(os_version)
- );
- CloseHandle(proc_handle);
- update_os(wd, os_name, os_version);
}
// try reading '/etc/redhatrelease'
//
if (!got_both(wd)) {
const std::string command_redhatrelease = "cat " + std::string(file_redhatrelease);
- if (!create_wsl_process(rs, wd.distro_name, command_redhatrelease, &proc_handle)) {
- continue;
+ if (!rs.run_command(
+ wd.distro_name, command_redhatrelease, &proc_handle
+ )) {
+ HOST_INFO::parse_linux_os_info(
+ read_from_pipe(proc_handle, rs.out_read),
+ redhatrelease, os_name, sizeof(os_name),
+ os_version, sizeof(os_version)
+ );
+ CloseHandle(proc_handle);
+ update_os(wd, os_name, os_version);
}
- HOST_INFO::parse_linux_os_info(
- read_from_pipe(proc_handle, rs.out_read),
- redhatrelease, os_name, sizeof(os_name),
- os_version, sizeof(os_version)
- );
- CloseHandle(proc_handle);
- update_os(wd, os_name, os_version);
}
std::string os_name_str = "";
@@ -429,21 +293,25 @@ int get_wsl_information(
//
if (!got_both(wd)) {
const std::string command_sysctl = "sysctl -a";
- if (create_wsl_process(rs, wd.distro_name, command_sysctl, &proc_handle)) {
+ if (!rs.run_command(
+ wd.distro_name, command_sysctl, &proc_handle
+ )) {
parse_sysctl_output(
split(read_from_pipe(proc_handle, rs.out_read), '\n'),
os_name_str, os_version_str
);
CloseHandle(proc_handle);
+ update_os(wd, os_name_str.c_str(), os_version_str.c_str());
}
- update_os(wd, os_name_str.c_str(), os_version_str.c_str());
}
// try running 'uname -s'
//
if (!got_both(wd)) {
const std::string command_uname_s = "uname -s";
- if (create_wsl_process(rs, wd.distro_name, command_uname_s, &proc_handle)) {
+ if (!rs.run_command(
+ wd.distro_name, command_uname_s, &proc_handle
+ )) {
os_name_str = read_from_pipe(proc_handle, rs.out_read);
strip_whitespace(os_name_str);
CloseHandle(proc_handle);
@@ -455,7 +323,9 @@ int get_wsl_information(
//
if (!got_both(wd)) {
const std::string command_uname_r = "uname -r";
- if (create_wsl_process(rs, wd.distro_name, command_uname_r ,&proc_handle)) {
+ if (!rs.run_command(
+ wd.distro_name, command_uname_r ,&proc_handle
+ )) {
os_version_str = read_from_pipe(proc_handle, rs.out_read);
strip_whitespace(os_version_str);
CloseHandle(proc_handle);
@@ -469,8 +339,8 @@ int get_wsl_information(
// see if Docker is installed in the distro
//
if (detect_docker) {
- if (create_wsl_process(
- rs, wd.distro_name, command_get_docker_version, &proc_handle
+ if (!rs.run_command(
+ wd.distro_name, command_get_docker_version, &proc_handle
)) {
std::string raw = read_from_pipe(proc_handle, rs.out_read);
std::string version;
@@ -480,8 +350,8 @@ int get_wsl_information(
}
CloseHandle(proc_handle);
}
- if (create_wsl_process(
- rs, wd.distro_name, command_get_docker_compose_version, &proc_handle
+ if (!rs.run_command(
+ wd.distro_name, command_get_docker_compose_version, &proc_handle
)) {
std::string raw = read_from_pipe(proc_handle, rs.out_read);
std::string version;
@@ -498,5 +368,3 @@ int get_wsl_information(
return 0;
}
-
-#endif // _WIN64
diff --git a/lib/sched_msgs.h b/lib/sched_msgs.h
index 1c35be3e03a..46deb290c28 100644
--- a/lib/sched_msgs.h
+++ b/lib/sched_msgs.h
@@ -27,7 +27,6 @@ class SCHED_MSG_LOG : public MSG_LOG {
const char* v_format_kind(int kind) const;
bool v_message_wanted(int kind) const;
public:
- enum { MSG_CRITICAL=1, MSG_WARNING, MSG_NORMAL, MSG_DEBUG, MSG_DETAIL };
SCHED_MSG_LOG(): MSG_LOG(stderr) { debug_level = MSG_NORMAL; }
void set_file(FILE* f) {output=f;}
void set_debug_level(int new_level) { debug_level = new_level; }
diff --git a/lib/win_util.cpp b/lib/win_util.cpp
index 1d76ffd68c1..d9b70f9cc97 100644
--- a/lib/win_util.cpp
+++ b/lib/win_util.cpp
@@ -26,9 +26,8 @@
#include "str_replace.h"
#include "str_util.h"
-/**
- * This function terminates a process by process id instead of a handle.
- **/
+// terminate a process by process ID instead of a handle.
+//
BOOL TerminateProcessById( DWORD dwProcessID ) {
HANDLE hProcess;
BOOL bRetVal = FALSE;
@@ -118,20 +117,30 @@ void chdir_to_data_dir() {
if (lpszExpandedValue) free(lpszExpandedValue);
}
+// convert string to wide string
+//
std::wstring boinc_ascii_to_wide(const std::string& str) {
- int length_wide = MultiByteToWideChar(CP_ACP, 0, str.data(), -1, NULL, 0);
- wchar_t *string_wide = static_cast(_alloca((length_wide * sizeof(wchar_t)) + sizeof(wchar_t)));
- MultiByteToWideChar(CP_ACP, 0, str.data(), -1, string_wide, length_wide);
- std::wstring result(string_wide, length_wide - 1);
- return result;
+ int length_wide = MultiByteToWideChar(CP_ACP, 0, str.data(), -1, NULL, 0);
+ wchar_t *string_wide = static_cast(
+ _alloca((length_wide * sizeof(wchar_t)) + sizeof(wchar_t))
+ );
+ MultiByteToWideChar(CP_ACP, 0, str.data(), -1, string_wide, length_wide);
+ std::wstring result(string_wide, length_wide - 1);
+ return result;
}
+// convert wide string to string
+//
std::string boinc_wide_to_ascii(const std::wstring& str) {
- int length_ansi = WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, NULL, 0, NULL, NULL);
- char* string_ansi = static_cast(_alloca(length_ansi + sizeof(char)));
- WideCharToMultiByte(CP_UTF8, 0, str.data(), -1, string_ansi, length_ansi, NULL, NULL);
- std::string result(string_ansi, length_ansi - 1);
- return result;
+ int length_ansi = WideCharToMultiByte(
+ CP_UTF8, 0, str.data(), -1, NULL, 0, NULL, NULL
+ );
+ char* string_ansi = static_cast(_alloca(length_ansi + sizeof(char)));
+ WideCharToMultiByte(
+ CP_UTF8, 0, str.data(), -1, string_ansi, length_ansi, NULL, NULL
+ );
+ std::string result(string_ansi, length_ansi - 1);
+ return result;
}
// get message for given error
@@ -177,3 +186,50 @@ char* windows_format_error_string(
return pszBuf;
}
+
+// WSL_CMD: run commands in a WSL distro
+
+typedef HRESULT(WINAPI *PWslLaunch)(
+ PCWSTR, PCWSTR, BOOL, HANDLE, HANDLE, HANDLE, HANDLE*
+);
+
+static PWslLaunch pWslLaunch = NULL;
+static HINSTANCE wsl_lib = NULL;
+
+int WSL_CMD::setup() {
+ in_read = NULL;
+ in_write = NULL;
+ out_read = NULL;
+ out_write = NULL;
+
+ if (!pWslLaunch) {
+ wsl_lib = LoadLibraryA("wslapi.dll");
+ if (!wsl_lib) return -1;
+ pWslLaunch = (PWslLaunch)GetProcAddress(wsl_lib, "WslLaunch");
+ if (!pWslLaunch) return -1;
+ }
+
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe(&out_read, &out_write, &sa, 0)) return -1;
+ if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) return -1;
+ if (!CreatePipe(&in_read, &in_write, &sa, 0)) return -1;
+ if (!SetHandleInformation(in_write, HANDLE_FLAG_INHERIT, 0)) return -1;
+ return 0;
+}
+
+int WSL_CMD::run_command(
+ const std::string distro_name, const std::string command,
+ HANDLE* proc_handle, bool use_cwd
+) {
+ HRESULT ret = pWslLaunch(
+ boinc_ascii_to_wide(distro_name).c_str(),
+ boinc_ascii_to_wide(command).c_str(),
+ use_cwd, in_read, out_write, out_write,
+ proc_handle
+ );
+ return (ret == S_OK)?0:-1;
+}
diff --git a/lib/win_util.h b/lib/win_util.h
index 35345e70e4c..4dadc85b961 100644
--- a/lib/win_util.h
+++ b/lib/win_util.h
@@ -28,4 +28,29 @@ extern char* windows_format_error_string(
unsigned long dwError, char* pszBuf, int iSize ...
);
+// struct for running a WSL command, connected via pipes
+//
+struct WSL_CMD {
+ HANDLE in_read = NULL;
+ HANDLE in_write = NULL;
+ HANDLE out_read = NULL;
+ HANDLE out_write = NULL;
+
+ ~WSL_CMD() {
+ if (in_read) CloseHandle(in_read);
+ if (in_write) CloseHandle(in_write);
+ if (out_read) CloseHandle(out_read);
+ if (out_write) CloseHandle(out_write);
+ }
+
+ int setup();
+
+ // run command, direct both stdout and stderr to the out pipe
+ //
+ int run_command(
+ const std::string distro_name, const std::string command,
+ HANDLE* proc_handle, bool use_cwd = false
+ );
+};
+
#endif
diff --git a/lib/wslinfo.cpp b/lib/wslinfo.cpp
index c391c7c81a1..8e6b9582afd 100644
--- a/lib/wslinfo.cpp
+++ b/lib/wslinfo.cpp
@@ -17,10 +17,6 @@
#include "wslinfo.h"
-WSL_DISTRO::WSL_DISTRO() {
- clear();
-}
-
void WSL_DISTRO::clear() {
distro_name = "";
os_name = "";
diff --git a/lib/wslinfo.h b/lib/wslinfo.h
index 613a46af255..ba041dca4d1 100644
--- a/lib/wslinfo.h
+++ b/lib/wslinfo.h
@@ -15,6 +15,9 @@
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see .
+// structs describing WSL (Windows Subsystem for Linux) distros.
+// Used in Win client and also in server code (for plan class logic)
+
#ifndef BOINC_WSLINFO_H
#define BOINC_WSLINFO_H
@@ -45,7 +48,9 @@ struct WSL_DISTRO {
std::string docker_compose_version;
// version of Docker Compose
- WSL_DISTRO();
+ WSL_DISTRO(){
+ clear();
+ };
void clear();
void write_xml(MIOFILE&);
int parse(XML_PARSER&);