Skip to content

Commit

Permalink
Merge pull request #7 from LuuuXXX/dev-luuuxxx
Browse files Browse the repository at this point in the history
Dev luuuxxx
  • Loading branch information
J-ZhengLi authored Jul 24, 2024
2 parents 0a62410 + 0e2f946 commit aa0c2b2
Show file tree
Hide file tree
Showing 5 changed files with 260 additions and 0 deletions.
19 changes: 19 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,22 @@ indicatif = "0.17"
reqwest = { version = "0.12", features = ["blocking"] }
serde = { version = "1", features = ["derive"] }
url = "2"
libc = "0.2"

[target."cfg(windows)".dependencies.windows-sys]
features = [
"Win32_Foundation",
"Win32_Security",
"Win32_Storage_FileSystem",
"Win32_System_Diagnostics_ToolHelp",
"Win32_System_IO",
"Win32_System_Ioctl",
"Win32_System_JobObjects",
"Win32_System_Kernel",
"Win32_System_LibraryLoader",
"Win32_System_SystemInformation",
"Win32_System_SystemServices",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
]
version = "0.52.0"
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub mod cli;
pub mod rustup;
pub mod utils;
39 changes: 39 additions & 0 deletions src/rustup.rs
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")
}
}
2 changes: 2 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
mod download;
mod file_system;
mod process;
mod triple;

pub use download::cli;
pub use file_system::*;
pub use process::*;
pub use triple::HostTriple;

use anyhow::{Context, Result};
use url::Url;
Expand Down
199 changes: 199 additions & 0 deletions src/utils/triple.rs
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"))
}

0 comments on commit aa0c2b2

Please sign in to comment.