From 8d1af908bf434b1af6624af4b8df54079d317ece Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Mon, 5 Oct 2020 20:29:47 -0700 Subject: [PATCH] fixup starting mux on windows * Taught wezterm-mux-server how to `--daemonize` on windows * Removed pty based command spawn used to spawn unix domain servers. This was present because it was the only way to successfully spawn wsl in the past. What I'm finding today is that it doesn't work at all for me, generating an `0xc0000142` Application failed to initialize error. A plain command builder spawn seems to work, so that's what we're going with. * Ensure that we put `.exe` on executable name on windows, otherwise the spawn may fail. * `Path::exists()` always returns false for unix domain sockets on Windows, so unconditionally try to remove the socket before binding, otherwise the bind will falsely fail, claiming that another process is already bound. The docs for mux will need to be updated to show how to revise them for the new mux server invocation: ```lua unix_domains = { { name = "wsl", serve_command = {"wsl", "wezterm-mux-server", "--daemonize"} }, } ``` --- Cargo.lock | 1 + config/src/unix.rs | 6 ++++- wezterm-mux-server/Cargo.toml | 1 + wezterm-mux-server/src/local.rs | 12 ++++++++-- wezterm-mux-server/src/main.rs | 28 +++++++++++++++++++++++ wezterm/src/server/client.rs | 40 ++++++++++++++------------------- 6 files changed, 62 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67f75175d..50161d04a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4110,6 +4110,7 @@ dependencies = [ "umask", "url", "wezterm-term", + "winapi 0.3.9", ] [[package]] diff --git a/config/src/unix.rs b/config/src/unix.rs index fad81a4d4..93f85edca 100644 --- a/config/src/unix.rs +++ b/config/src/unix.rs @@ -67,7 +67,11 @@ impl UnixDomain { Some(cmd) => Ok(cmd.iter().map(Into::into).collect()), None => Ok(vec![ std::env::current_exe()? - .with_file_name("wezterm-mux-server") + .with_file_name(if cfg!(windows) { + "wezterm-mux-server.exe" + } else { + "wezterm-mux-server" + }) .into_os_string(), OsString::from("--daemonize"), ]), diff --git a/wezterm-mux-server/Cargo.toml b/wezterm-mux-server/Cargo.toml index 012816bfb..646ddf111 100644 --- a/wezterm-mux-server/Cargo.toml +++ b/wezterm-mux-server/Cargo.toml @@ -36,3 +36,4 @@ vendor_openssl = ["openssl/vendored"] [target."cfg(windows)".dependencies] uds_windows = "0.1" +winapi = { version = "0.3", features = [ "winuser" ]} diff --git a/wezterm-mux-server/src/local.rs b/wezterm-mux-server/src/local.rs index 9abc1f1a8..ae5cf3760 100644 --- a/wezterm-mux-server/src/local.rs +++ b/wezterm-mux-server/src/local.rs @@ -73,8 +73,16 @@ fn safely_create_sock_path(unix_dom: &UnixDomain) -> anyhow::Result {} + Err(err) => match err.kind() { + std::io::ErrorKind::NotFound => {} + _ => return Err(err).context(format!("Unable to remove {}", sock_path.display())), + }, } UnixListener::bind(sock_path) diff --git a/wezterm-mux-server/src/main.rs b/wezterm-mux-server/src/main.rs index cf26b8996..ab0cdb8e9 100644 --- a/wezterm-mux-server/src/main.rs +++ b/wezterm-mux-server/src/main.rs @@ -69,6 +69,34 @@ fn run() -> anyhow::Result<()> { } } + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + use std::process::Command; + // We can't literally daemonize, but we can spawn another copy + // of ourselves in the background! + if opts.daemonize { + let mut cmd = Command::new(std::env::current_exe().unwrap()); + if opts.skip_config { + cmd.arg("-n"); + } + if let Some(cwd) = opts.cwd { + cmd.arg("--cwd"); + cmd.arg(cwd); + } + if !opts.prog.is_empty() { + cmd.arg("--"); + for a in &opts.prog { + cmd.arg(a); + } + } + cmd.creation_flags(winapi::um::winbase::DETACHED_PROCESS); + let child = cmd.spawn(); + drop(child); + return Ok(()); + } + } + // Remove some environment variables that aren't super helpful or // that are potentially misleading when we're starting up the // server. diff --git a/wezterm/src/server/client.rs b/wezterm/src/server/client.rs index 107a36459..8f84748f4 100644 --- a/wezterm/src/server/client.rs +++ b/wezterm/src/server/client.rs @@ -15,7 +15,6 @@ use mux::pane::PaneId; use mux::Mux; use openssl::ssl::{SslConnector, SslFiletype, SslMethod}; use openssl::x509::X509; -use portable_pty::{CommandBuilder, NativePtySystem, PtySystem}; use smol::channel::{bounded, unbounded, Receiver, Sender}; use smol::prelude::*; use smol::{block_on, Async}; @@ -503,29 +502,24 @@ impl Reconnectable { let argv = unix_dom.serve_command()?; - // We need to use a pty to spawn the command because, - // on Windows, when spawned from the gui with no pre-existing - // conhost.exe, `wsl.exe` will fail to start up correctly. - // This also has a nice side effect of not flashing up a - // console window when we first spin up the wsl instance. - let pty_system = NativePtySystem::default(); - let pair = pty_system.openpty(Default::default())?; - let mut cmd = CommandBuilder::new(&argv[0]); + let mut cmd = std::process::Command::new(&argv[0]); cmd.args(&argv[1..]); - let mut child = pair.slave.spawn_command(cmd)?; - drop(pair.slave); - let mut reader = pair.master.try_clone_reader()?; - drop(pair.master); - let mut s = String::new(); - reader.read_to_string(&mut s).ok(); - log::error!("server output: {}", s); - - let status = child.wait()?; - if !status.success() { - log::error!("{:?} failed with status {:?}", argv, status); - } - log::error!("{:?} completed with status {:?}", argv, status); - drop(child); + let child = cmd + .spawn() + .with_context(|| format!("while spawning {:?}", cmd))?; + std::thread::spawn(move || match child.wait_with_output() { + Ok(out) => { + if let Ok(stdout) = std::str::from_utf8(&out.stdout) { + log::error!("stdout: {}", stdout); + } + if let Ok(stderr) = std::str::from_utf8(&out.stderr) { + log::error!("stderr: {}", stderr); + } + } + Err(err) => { + log::error!("spawn: {:#}", err); + } + }); unix_connect_with_retry(&sock_path, true).with_context(|| { format!(