1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-23 13:21:38 +03:00

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"}
    },
  }
```
This commit is contained in:
Wez Furlong 2020-10-05 20:29:47 -07:00
parent a9a220f43c
commit 8d1af908bf
6 changed files with 62 additions and 26 deletions

1
Cargo.lock generated
View File

@ -4110,6 +4110,7 @@ dependencies = [
"umask", "umask",
"url", "url",
"wezterm-term", "wezterm-term",
"winapi 0.3.9",
] ]
[[package]] [[package]]

View File

@ -67,7 +67,11 @@ impl UnixDomain {
Some(cmd) => Ok(cmd.iter().map(Into::into).collect()), Some(cmd) => Ok(cmd.iter().map(Into::into).collect()),
None => Ok(vec![ None => Ok(vec![
std::env::current_exe()? 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(), .into_os_string(),
OsString::from("--daemonize"), OsString::from("--daemonize"),
]), ]),

View File

@ -36,3 +36,4 @@ vendor_openssl = ["openssl/vendored"]
[target."cfg(windows)".dependencies] [target."cfg(windows)".dependencies]
uds_windows = "0.1" uds_windows = "0.1"
winapi = { version = "0.3", features = [ "winuser" ]}

View File

@ -73,8 +73,16 @@ fn safely_create_sock_path(unix_dom: &UnixDomain) -> anyhow::Result<UnixListener
} }
} }
if sock_path.exists() { // We want to remove the socket if it exists.
std::fs::remove_file(sock_path)?; // However, on windows, we can't tell if the unix domain socket
// exists using the methods on Path, so instead we just unconditionally
// remove it and see what error occurs.
match std::fs::remove_file(sock_path) {
Ok(_) => {}
Err(err) => match err.kind() {
std::io::ErrorKind::NotFound => {}
_ => return Err(err).context(format!("Unable to remove {}", sock_path.display())),
},
} }
UnixListener::bind(sock_path) UnixListener::bind(sock_path)

View File

@ -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 // Remove some environment variables that aren't super helpful or
// that are potentially misleading when we're starting up the // that are potentially misleading when we're starting up the
// server. // server.

View File

@ -15,7 +15,6 @@ use mux::pane::PaneId;
use mux::Mux; use mux::Mux;
use openssl::ssl::{SslConnector, SslFiletype, SslMethod}; use openssl::ssl::{SslConnector, SslFiletype, SslMethod};
use openssl::x509::X509; use openssl::x509::X509;
use portable_pty::{CommandBuilder, NativePtySystem, PtySystem};
use smol::channel::{bounded, unbounded, Receiver, Sender}; use smol::channel::{bounded, unbounded, Receiver, Sender};
use smol::prelude::*; use smol::prelude::*;
use smol::{block_on, Async}; use smol::{block_on, Async};
@ -503,29 +502,24 @@ impl Reconnectable {
let argv = unix_dom.serve_command()?; let argv = unix_dom.serve_command()?;
// We need to use a pty to spawn the command because, let mut cmd = std::process::Command::new(&argv[0]);
// 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]);
cmd.args(&argv[1..]); cmd.args(&argv[1..]);
let mut child = pair.slave.spawn_command(cmd)?; let child = cmd
drop(pair.slave); .spawn()
let mut reader = pair.master.try_clone_reader()?; .with_context(|| format!("while spawning {:?}", cmd))?;
drop(pair.master); std::thread::spawn(move || match child.wait_with_output() {
let mut s = String::new(); Ok(out) => {
reader.read_to_string(&mut s).ok(); if let Ok(stdout) = std::str::from_utf8(&out.stdout) {
log::error!("server output: {}", s); log::error!("stdout: {}", stdout);
let status = child.wait()?;
if !status.success() {
log::error!("{:?} failed with status {:?}", argv, status);
} }
log::error!("{:?} completed with status {:?}", argv, status); if let Ok(stderr) = std::str::from_utf8(&out.stderr) {
drop(child); log::error!("stderr: {}", stderr);
}
}
Err(err) => {
log::error!("spawn: {:#}", err);
}
});
unix_connect_with_retry(&sock_path, true).with_context(|| { unix_connect_with_retry(&sock_path, true).with_context(|| {
format!( format!(