Skip to content

Commit

Permalink
[yabridgectl] Fix setup checks with 32-bit prefix
Browse files Browse the repository at this point in the history
This will now run `yabridge-host-32.exe` if `~/.wine` was created with
`WINEARCH=win32`.
  • Loading branch information
robbert-vdh committed Jun 25, 2021
1 parent 6573b01 commit 5133f07
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Expand Up @@ -70,6 +70,11 @@ Versioning](https://semver.org/spec/v2.0.0.html).

- Added support for setting up merged VST3 bundles with a 32-bit version of
`libyabridge-vst3.so`.
- Fixed the post-installation setup checks when the default Wine prefix over at
`~/.wine` was created with `WINEARCH=win32` set. This would otherwise result
in an `00cc:err:process:exec_process` error when running `yabridgectl sync`
because yabridgectl would try to run the 64-bit `yabridge-host.exe` in that
prefix.
- Merged VST3 bundles set up in `~/.vst3/yabridge` are now always cleared before
yabridgectl adds new files to them. This makes it easier to switch from the
64-bit version of a plugin to the 32-bit version, or from a 64-bit version of
Expand Down
35 changes: 24 additions & 11 deletions tools/yabridgectl/src/config.rs
Expand Up @@ -42,6 +42,10 @@ pub const LIBYABRIDGE_VST2_NAME: &str = "libyabridge-vst2.so";
pub const LIBYABRIDGE_VST3_NAME: &str = "libyabridge-vst3.so";
/// The name of the script we're going to run to verify that everything's working correctly.
pub const YABRIDGE_HOST_EXE_NAME: &str = "yabridge-host.exe";
/// The 32-bit verison of `YABRIDGE_HOST_EXE_NAME`. If `~/.wine` was somehow created with
/// `WINEARCH=win32` set, then it won't be possible to run the 64-bit `yabridge-host.exe` in there.
/// In that case we'll just run the 32-bit version isntead, if it exists.
pub const YABRIDGE_HOST_32_EXE_NAME: &str = "yabridge-host-32.exe";
/// The name of the XDG base directory prefix for yabridge's own files, relative to
/// `$XDG_CONFIG_HOME` and `$XDG_DATA_HOME`.
const YABRIDGE_PREFIX: &str = "yabridge";
Expand Down Expand Up @@ -149,10 +153,15 @@ pub struct YabridgeFiles {
pub libyabridge_vst3: Option<(PathBuf, LibArchitecture)>,
/// The path to `yabridge-host.exe`. This is the path yabridge will actually use, and it does
/// not have to be relative to `yabridge_home`.
pub yabridge_host_exe: PathBuf,
pub yabridge_host_exe: Option<PathBuf>,
/// The actual Winelib binary for `yabridge-host.exe`. Will be hashed to check whether the user
/// has updated yabridge.
pub yabridge_host_exe_so: PathBuf,
pub yabridge_host_exe_so: Option<PathBuf>,
/// The same as `yabridge_host_exe`, but for the 32-bit verison.
pub yabridge_host_32_exe: Option<PathBuf>,
/// The same as `yabridge_host_exe_so`, but for the 32-bit verison. We will hash this instead of
/// there's no 64-bit version available.
pub yabridge_host_32_exe_so: Option<PathBuf>,
}

impl Default for Config {
Expand Down Expand Up @@ -279,22 +288,26 @@ impl Config {

// `yabridge-host.exe` should either be in the search path, or it should be in
// `~/.local/share/yabridge`
let yabridge_host_exe = match which(YABRIDGE_HOST_EXE_NAME)
let yabridge_host_exe = which(YABRIDGE_HOST_EXE_NAME)
.ok()
.or_else(|| xdg_dirs.find_data_file(YABRIDGE_HOST_EXE_NAME))
{
Some(path) => path,
_ => {
return Err(anyhow!("Could not locate '{}'.", YABRIDGE_HOST_EXE_NAME));
}
};
let yabridge_host_exe_so = yabridge_host_exe.with_extension("exe.so");
.or_else(|| xdg_dirs.find_data_file(YABRIDGE_HOST_EXE_NAME));
let yabridge_host_exe_so = yabridge_host_exe
.as_ref()
.map(|path| path.with_extension("exe.so"));
let yabridge_host_32_exe = which(YABRIDGE_HOST_32_EXE_NAME)
.ok()
.or_else(|| xdg_dirs.find_data_file(YABRIDGE_HOST_32_EXE_NAME));
let yabridge_host_32_exe_so = yabridge_host_32_exe
.as_ref()
.map(|path| path.with_extension("exe.so"));

Ok(YabridgeFiles {
libyabridge_vst2,
libyabridge_vst3,
yabridge_host_exe,
yabridge_host_exe_so,
yabridge_host_32_exe,
yabridge_host_32_exe_so,
})
}

Expand Down
56 changes: 50 additions & 6 deletions tools/yabridgectl/src/utils.rs
Expand Up @@ -23,14 +23,14 @@ use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs;
use std::hash::Hasher;
use std::io::{Read, Seek, SeekFrom};
use std::io::{BufRead, BufReader, Read, Seek, SeekFrom};
use std::os::unix::fs as unix_fs;
use std::os::unix::process::CommandExt;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use textwrap::Wrapper;

use crate::config::{self, Config, KnownConfig, YABRIDGE_HOST_EXE_NAME};
use crate::config::{self, Config, KnownConfig, YABRIDGE_HOST_32_EXE_NAME, YABRIDGE_HOST_EXE_NAME};
use crate::files::{LibArchitecture, NativeFile};

/// (Part of) the expected output when running `yabridge-host.exe`. Used to verify that everything's
Expand Down Expand Up @@ -132,6 +132,33 @@ pub fn get_file_type(path: PathBuf) -> Option<NativeFile> {
}
}

/// Get the architecture (either 64-bit or 32-bit) of the default Wine prefix in `~/.wine`. Defaults
/// to 64-bit if `~/.wine` doesn't exist or if the prefix is invalid.
pub fn get_default_wine_prefix_arch() -> LibArchitecture {
let wine_system_reg_path = PathBuf::from(env::var("HOME").expect("$HOME is not set"))
.join(".wine")
.join("system.reg");

// Fall back to 64-bit if the prefix doesn't exist
let wine_system_reg = match fs::File::open(wine_system_reg_path) {
Ok(file) => file,
_ => return LibArchitecture::Lib64,
};

for line in BufReader::new(wine_system_reg)
.lines()
.filter_map(|l| l.ok())
{
match line.as_str() {
"#arch=win32" => return LibArchitecture::Lib32,
"#arch=win64" => break,
_ => (),
};
}

LibArchitecture::Lib64
}

/// Hash the conetnts of a file as an `i64` using Rust's built in hasher. Collisions are not a big
/// issue in our situation so we can get away with this.
///
Expand Down Expand Up @@ -310,8 +337,14 @@ pub fn verify_wine_setup(config: &mut Config) -> Result<()> {
.context(format!("Could not find '{}'", YABRIDGE_HOST_EXE_NAME))?;

// Hash the contents of `yabridge-host.exe.so` since `yabridge-host.exe` is only a Wine
// generated shell script
let yabridge_host_hash = hash_file(&files.yabridge_host_exe_so)?;
// generated shell script. If somehow only the 32-bit verison is installed, we'll just hash that
// one.
let yabridge_host_hash = hash_file(
&files
.yabridge_host_exe_so
.or(files.yabridge_host_32_exe_so)
.with_context(|| format!("Could not locate '{}.so'", YABRIDGE_HOST_EXE_NAME))?,
)?;

// Since these checks can take over a second if wineserver isn't already running we'll only
// perform them when something has changed
Expand All @@ -323,9 +356,20 @@ pub fn verify_wine_setup(config: &mut Config) -> Result<()> {
return Ok(());
}

let output = Command::new(&files.yabridge_host_exe)
// It could be that the default Wine prefix was created with `WINEARCH=win32` set. In that case
// we should run the 32-bit `yabridge-host.exe` since the 64-bit verison won't be able to run.
let host_binary_path = match get_default_wine_prefix_arch() {
LibArchitecture::Lib32 => files
.yabridge_host_32_exe
.with_context(|| format!("Could not find '{}'", YABRIDGE_HOST_32_EXE_NAME)),
LibArchitecture::Lib64 => files
.yabridge_host_exe
.with_context(|| format!("Could not find '{}'", YABRIDGE_HOST_EXE_NAME)),
}?;

let output = Command::new(&host_binary_path)
.output()
.with_context(|| format!("Could not run '{}'", files.yabridge_host_exe.display()))?;
.with_context(|| format!("Could not run '{}'", host_binary_path.display()))?;
let stderr = String::from_utf8(output.stderr)?;

// There are three scenarios here:
Expand Down

0 comments on commit 5133f07

Please sign in to comment.