From: André Zwing nerv@dawncrow.de
--- tools/wine/Makefile.in | 2 +- tools/wine/wine.c | 67 -------------- tools/wine/wine.rs | 194 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 68 deletions(-) delete mode 100644 tools/wine/wine.c create mode 100644 tools/wine/wine.rs
diff --git a/tools/wine/Makefile.in b/tools/wine/Makefile.in index 55489a3444a..7c668cabc41 100644 --- a/tools/wine/Makefile.in +++ b/tools/wine/Makefile.in @@ -1,7 +1,7 @@ PROGRAMS = wine
SOURCES = \ - wine.c \ + wine.rs \ wine.de.UTF-8.man.in \ wine.fr.UTF-8.man.in \ wine.man.in \ diff --git a/tools/wine/wine.c b/tools/wine/wine.c deleted file mode 100644 index 32157dfd4bc..00000000000 --- a/tools/wine/wine.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Loader for Wine installed in the bin directory - * - * Copyright 2025 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include "config.h" - -#include "../tools.h" - -#include <dlfcn.h> - -static const char *bindir; -static const char *libdir; - -static void *load_ntdll(void) -{ - const char *arch_dir = get_arch_dir( get_default_target() ); - struct strarray dllpath; - void *handle; - unsigned int i; - - if (bindir && strendswith( bindir, "/tools/wine" ) && - ((handle = dlopen( strmake( "%s/../../dlls/ntdll/ntdll.so", bindir ), RTLD_NOW )))) - return handle; - - if ((handle = dlopen( strmake( "%s/wine%s/ntdll.so", libdir, arch_dir ), RTLD_NOW ))) - return handle; - - dllpath = strarray_frompath( getenv( "WINEDLLPATH" )); - for (i = 0; i < dllpath.count; i++) - { - if ((handle = dlopen( strmake( "%s%s/ntdll.so", dllpath.str[i], arch_dir ), RTLD_NOW ))) - return handle; - if ((handle = dlopen( strmake( "%s/ntdll.so", dllpath.str[i] ), RTLD_NOW ))) - return handle; - } - fprintf( stderr, "wine: could not load ntdll.so: %s\n", dlerror() ); - exit(1); -} - -int main( int argc, char *argv[] ) -{ - void (*init_func)(int, char **); - - bindir = get_bindir( argv[0] ); - libdir = get_libdir( bindir ); - init_func = dlsym( load_ntdll(), "__wine_main" ); - if (init_func) init_func( argc, argv ); - - fprintf( stderr, "wine: __wine_main function not found in ntdll.so\n" ); - exit(1); -} diff --git a/tools/wine/wine.rs b/tools/wine/wine.rs new file mode 100644 index 00000000000..17eb99586e4 --- /dev/null +++ b/tools/wine/wine.rs @@ -0,0 +1,194 @@ +/* + * Loader for Wine installed in the bin directory + * + * Copyright 2025 Alexandre Julliard + * Copyright 2025 André Zwing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +use libloading::{Library, Symbol}; +use std::{env, ffi::CString, fs::canonicalize, process::exit}; + +#[cfg(target_os = "linux")] +fn get_bindir(argv0: &str) -> Option<String> { + if let Ok(real_path) = canonicalize("/proc/self/exe") { + return Some(real_path.parent()?.to_str()?.to_string()); + } + canonicalize(argv0) + .ok()? + .parent()? + .to_str() + .map(|s| s.to_string()) +} + +#[cfg(target_os = "windows")] +fn get_bindir(_argv0: &str) -> Option<String> { + use std::ptr; + use winapi::um::{libloaderapi::GetModuleFileNameA, winnt::MAX_PATH}; + + let mut path = vec![0u8; MAX_PATH as usize]; + unsafe { + GetModuleFileNameA(ptr::null_mut(), path.as_mut_ptr() as *mut i8, MAX_PATH); + } + let path_str = String::from_utf8_lossy(&path); + Some( + PathBuf::from(path_str.trim_end_matches(char::from(0))) + .parent()? + .to_str()? + .to_string(), + ) +} + +fn get_libdir(bindir: &str) -> String { + format!("{}/../lib", bindir) +} + +#[allow(dead_code)] +#[derive(Debug)] +struct Target { + cpu: &'static str, + platform: &'static str, +} + +fn get_default_target() -> Target { + let cpu = if cfg!(target_arch = "x86") { + "i386" + } else if cfg!(target_arch = "x86_64") { + "x86_64" + } else if cfg!(target_arch = "arm") { + "arm" + } else if cfg!(target_arch = "aarch64") { + "aarch64" + } else { + panic!("Unsupported CPU"); + }; + + let platform = if cfg!(target_os = "macos") { + "apple" + } else if cfg!(target_os = "android") { + "android" + } else if cfg!(target_os = "linux") { + "linux" + } else if cfg!(target_os = "freebsd") { + "freebsd" + } else if cfg!(target_os = "solaris") { + "solaris" + } else if cfg!(target_os = "windows") { + "mingw" + } else { + "unspecified" + }; + + Target { cpu, platform } +} + +fn get_arch_dir(target: &Target) -> String { + let cpu_names = [ + ("i386", "i386"), + ("x86_64", "x86_64"), + ("arm", "arm"), + ("aarch64", "aarch64"), + ]; + + let cpu_name = cpu_names + .iter() + .find(|&&(key, _)| key == target.cpu) + .map(|&(_, name)| name); + if let Some(name) = cpu_name { + format!( + "/{}/{}", + name, + if is_pe_target(target) { + "windows" + } else { + "unix" + } + ) + } else { + "".to_string() + } +} + +fn is_pe_target(_target: &Target) -> bool { + // Implement platform-specific PE detection logic if needed + false +} + +fn load_ntdll(bindir_in: Option<String>, libdir_in: Option<String>) -> Library { + let arch_dir = get_arch_dir(&get_default_target()); + let winedllpath = env::var("WINEDLLPATH").unwrap_or_default(); + + unsafe { + if let Some(ref bindir) = bindir_in { + if bindir.ends_with("/tools/wine") { + let path = format!("{}/../../dlls/ntdll/ntdll.so", bindir); + if let Ok(lib) = Library::new(&path) { + return lib; + } + } + } + + if let Some(ref libdir) = libdir_in { + let path = format!("{}/wine{}/ntdll.so", libdir, arch_dir); + if let Ok(lib) = Library::new(&path) { + return lib; + } + } + + for path in winedllpath.split(':') { + let full_path1 = format!("{}{}{}/ntdll.so", path, arch_dir, ""); + if let Ok(lib) = Library::new(&full_path1) { + return lib; + } + let full_path2 = format!("{}/ntdll.so", path); + if let Ok(lib) = Library::new(&full_path2) { + return lib; + } + } + } + + eprintln!("wine: could not load ntdll.so"); + exit(1); +} + +fn main() { + let args: Vec<String> = env::args().collect(); + + let bindir: Option<String> = get_bindir(&args[0]); + let libdir: Option<String> = Some(get_libdir(bindir.as_ref().unwrap())); + + let ntdll = load_ntdll(bindir, libdir); + + unsafe { + let init_func: Result<Symbol<unsafe extern "C" fn(i32, *mut *mut i8)>, _> = + ntdll.get(b"__wine_main"); + + match init_func { + Ok(func) => { + let mut c_args: Vec<*mut i8> = args + .iter() + .map(|arg| CString::new(arg.as_str()).unwrap().into_raw()) + .collect(); + + func(args.len() as i32, c_args.as_mut_ptr()); + } + Err(_) => { + eprintln!("wine: __wine_main function not found in ntdll.so"); + exit(1); + } + } + } +}