-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from LuuuXXX/dev-luuuxxx
Dev luuuxxx
- Loading branch information
Showing
5 changed files
with
260 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
pub mod cli; | ||
pub mod rustup; | ||
pub mod utils; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
use std::path::Path; | ||
|
||
use anyhow::{Context, Result}; | ||
|
||
use crate::utils::cli::download_from_start; | ||
use crate::utils::HostTriple; | ||
|
||
const RUSTUP_DIST_SERVER: &str = "https://mirrors.tuna.tsinghua.edu.cn/rustup"; | ||
const RUSTUP_UPDATE_ROOT: &str = "https://mirrors.tuna.tsinghua.edu.cn/rustup/rustup"; | ||
|
||
#[cfg(windows)] | ||
const RUSTUP_INIT: &str = "rustup-init.exe"; | ||
#[cfg(not(windows))] | ||
const RUSTUP_INIT: &str = "rustup-init"; | ||
|
||
pub struct Rustup { | ||
triple: HostTriple, | ||
} | ||
|
||
impl Rustup { | ||
pub fn new() -> Self { | ||
let host_triple = match HostTriple::from_host() { | ||
Some(host_triple) => host_triple, | ||
None => panic!("Failed to get local host triple."), | ||
}; | ||
Self { | ||
triple: host_triple, | ||
} | ||
} | ||
|
||
pub fn download(&self, dest: &Path) -> Result<()> { | ||
let download_url = url::Url::parse(&format!( | ||
"{}/{}/{}/{}", | ||
RUSTUP_UPDATE_ROOT, "dist", self.triple, RUSTUP_INIT | ||
)) | ||
.context("Failed to init rustup download url")?; | ||
download_from_start(RUSTUP_INIT, &download_url, dest).context("Failed to download rustup") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
use std::{env, fmt, ops::Deref}; | ||
|
||
// Linux hosts don't indicate clib in uname, however binaries only | ||
// run on boxes with the same clib, as expected. | ||
#[cfg(all(not(windows), not(target_env = "musl")))] | ||
const TRIPLE_X86_64_UNKNOWN_LINUX: &str = "x86_64-unknown-linux-gnu"; | ||
#[cfg(all(not(windows), target_env = "musl"))] | ||
const TRIPLE_X86_64_UNKNOWN_LINUX: &str = "x86_64-unknown-linux-musl"; | ||
#[cfg(all(not(windows), not(target_env = "musl")))] | ||
const TRIPLE_AARCH64_UNKNOWN_LINUX: &str = "aarch64-unknown-linux-gnu"; | ||
#[cfg(all(not(windows), target_env = "musl"))] | ||
const TRIPLE_AARCH64_UNKNOWN_LINUX: &str = "aarch64-unknown-linux-musl"; | ||
#[cfg(all(not(windows), not(target_env = "musl")))] | ||
const TRIPLE_LOONGARCH64_UNKNOWN_LINUX: &str = "loongarch64-unknown-linux-gnu"; | ||
#[cfg(all(not(windows), target_env = "musl"))] | ||
const TRIPLE_LOONGARCH64_UNKNOWN_LINUX: &str = "loongarch64-unknown-linux-musl"; | ||
|
||
// MIPS platforms don't indicate endianness in uname, however binaries only | ||
// run on boxes with the same endianness, as expected. | ||
// Hence we could distinguish between the variants with compile-time cfg() | ||
// attributes alone. | ||
#[cfg(all(not(windows), target_endian = "big"))] | ||
static TRIPLE_MIPS_UNKNOWN_LINUX_GNU: &str = "mips-unknown-linux-gnu"; | ||
#[cfg(all(not(windows), target_endian = "little"))] | ||
static TRIPLE_MIPS_UNKNOWN_LINUX_GNU: &str = "mipsel-unknown-linux-gnu"; | ||
|
||
#[cfg(all(not(windows), target_endian = "big"))] | ||
static TRIPLE_MIPS64_UNKNOWN_LINUX_GNUABI64: &str = "mips64-unknown-linux-gnuabi64"; | ||
#[cfg(all(not(windows), target_endian = "little"))] | ||
static TRIPLE_MIPS64_UNKNOWN_LINUX_GNUABI64: &str = "mips64el-unknown-linux-gnuabi64"; | ||
|
||
#[derive(Debug)] | ||
pub struct HostTriple(String); | ||
|
||
impl HostTriple { | ||
pub fn new(name: impl Into<String>) -> Self { | ||
Self(name.into()) | ||
} | ||
|
||
pub(crate) fn from_host() -> Option<Self> { | ||
#[cfg(windows)] | ||
fn inner() -> Option<HostTriple> { | ||
use std::mem; | ||
|
||
/// Get the host architecture using `IsWow64Process2`. This function | ||
/// produces the most accurate results (supports detecting aarch64), but | ||
/// it is only available on Windows 10 1511+, so we use `GetProcAddress` | ||
/// to maintain backward compatibility with older Windows versions. | ||
fn arch_primary() -> Option<&'static str> { | ||
use windows_sys::core::s; | ||
use windows_sys::Win32::Foundation::{BOOL, HANDLE}; | ||
use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleA, GetProcAddress}; | ||
use windows_sys::Win32::System::Threading::GetCurrentProcess; | ||
|
||
const IMAGE_FILE_MACHINE_ARM64: u16 = 0xAA64; | ||
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664; | ||
const IMAGE_FILE_MACHINE_I386: u16 = 0x014c; | ||
|
||
#[allow(non_snake_case)] | ||
let IsWow64Process2: unsafe extern "system" fn( | ||
HANDLE, | ||
*mut u16, | ||
*mut u16, | ||
) | ||
-> BOOL = unsafe { | ||
let module = GetModuleHandleA(s!("kernel32.dll")); | ||
if module == 0 { | ||
return None; | ||
} | ||
mem::transmute(GetProcAddress(module, s!("IsWow64Process2"))?) | ||
}; | ||
|
||
let mut _machine = 0; | ||
let mut native_machine = 0; | ||
unsafe { | ||
// cannot fail; handle does not need to be closed. | ||
let process = GetCurrentProcess(); | ||
if IsWow64Process2(process, &mut _machine, &mut native_machine) == 0 { | ||
return None; | ||
} | ||
}; | ||
match native_machine { | ||
IMAGE_FILE_MACHINE_AMD64 => Some("x86_64"), | ||
IMAGE_FILE_MACHINE_I386 => Some("i686"), | ||
IMAGE_FILE_MACHINE_ARM64 => Some("aarch64"), | ||
_ => None, | ||
} | ||
} | ||
|
||
/// Get the host architecture using `GetNativeSystemInfo`. | ||
/// Does not support detecting aarch64. | ||
fn arch_fallback() -> Option<&'static str> { | ||
use windows_sys::Win32::System::SystemInformation::GetNativeSystemInfo; | ||
|
||
const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; | ||
const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; | ||
|
||
let mut sys_info; | ||
unsafe { | ||
sys_info = mem::zeroed(); | ||
GetNativeSystemInfo(&mut sys_info); | ||
} | ||
|
||
match unsafe { sys_info.Anonymous.Anonymous }.wProcessorArchitecture { | ||
PROCESSOR_ARCHITECTURE_AMD64 => Some("x86_64"), | ||
PROCESSOR_ARCHITECTURE_INTEL => Some("i686"), | ||
_ => None, | ||
} | ||
} | ||
|
||
// Default to msvc | ||
let arch = arch_primary().or_else(arch_fallback)?; | ||
let msvc_triple = format!("{arch}-pc-windows-msvc"); | ||
Some(HostTriple(msvc_triple)) | ||
} | ||
|
||
#[cfg(not(windows))] | ||
fn inner() -> Option<HostTriple> { | ||
use std::ffi::CStr; | ||
use std::mem; | ||
|
||
let mut sys_info; | ||
let (sysname, machine) = unsafe { | ||
sys_info = mem::zeroed(); | ||
if libc::uname(&mut sys_info) != 0 { | ||
return None; | ||
} | ||
|
||
( | ||
CStr::from_ptr(sys_info.sysname.as_ptr()).to_bytes(), | ||
CStr::from_ptr(sys_info.machine.as_ptr()).to_bytes(), | ||
) | ||
}; | ||
|
||
let host_triple = match (sysname, machine) { | ||
(b"Linux", b"x86_64") => Some(TRIPLE_X86_64_UNKNOWN_LINUX), | ||
(b"Linux", b"i686") => Some("i686-unknown-linux-gnu"), | ||
(b"Linux", b"mips") => Some(TRIPLE_MIPS_UNKNOWN_LINUX_GNU), | ||
(b"Linux", b"mips64") => Some(TRIPLE_MIPS64_UNKNOWN_LINUX_GNUABI64), | ||
(b"Linux", b"arm") => Some("arm-unknown-linux-gnueabi"), | ||
(b"Linux", b"armv7l") => Some("armv7-unknown-linux-gnueabihf"), | ||
(b"Linux", b"armv8l") => Some("armv7-unknown-linux-gnueabihf"), | ||
(b"Linux", b"aarch64") => Some(if is_32bit_userspace() { | ||
"armv7-unknown-linux-gnueabihf" | ||
} else { | ||
TRIPLE_AARCH64_UNKNOWN_LINUX | ||
}), | ||
(b"Linux", b"loongarch64") => Some(TRIPLE_LOONGARCH64_UNKNOWN_LINUX), | ||
(b"Darwin", b"x86_64") => Some("x86_64-apple-darwin"), | ||
(b"Darwin", b"i686") => Some("i686-apple-darwin"), | ||
_ => None, | ||
}; | ||
|
||
host_triple.map(HostTriple::new) | ||
} | ||
|
||
if let Ok(triple) = env::var("XUANWU_OVERRIDE_HOST_TRPLE") { | ||
Some(Self(triple)) | ||
} else { | ||
inner() | ||
} | ||
} | ||
} | ||
|
||
impl Deref for HostTriple { | ||
type Target = str; | ||
fn deref(&self) -> &Self::Target { | ||
&self.0 | ||
} | ||
} | ||
|
||
impl fmt::Display for HostTriple { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
self.0.fmt(f) | ||
} | ||
} | ||
|
||
/// Check if /bin/sh is a 32-bit binary. If it doesn't exist, fall back to | ||
/// checking if _we_ are a 32-bit binary. | ||
/// rustup-init.sh also relies on checking /bin/sh for bitness. | ||
#[cfg(not(windows))] | ||
fn is_32bit_userspace() -> bool { | ||
use std::fs; | ||
use std::io::{self, Read}; | ||
|
||
// inner function is to simplify error handling. | ||
fn inner() -> io::Result<bool> { | ||
let mut f = fs::File::open("/bin/sh")?; | ||
let mut buf = [0; 5]; | ||
f.read_exact(&mut buf)?; | ||
|
||
// ELF files start out "\x7fELF", and the following byte is | ||
// 0x01 for 32-bit and | ||
// 0x02 for 64-bit. | ||
Ok(&buf == b"\x7fELF\x01") | ||
} | ||
|
||
inner().unwrap_or(cfg!(target_pointer_width = "32")) | ||
} |