You've already forked platform-info
mirror of
https://github.com/uutils/platform-info.git
synced 2026-06-10 15:48:45 -07:00
Add Windows support and enable CI
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
[target.x86_64-unknown-redox]
|
||||
linker = "x86_64-unknown-redox-gcc"
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
# Based on the "trust" template v0.1.2
|
||||
# https://github.com/japaric/trust/tree/v0.1.2
|
||||
|
||||
dist: trusty
|
||||
language: rust
|
||||
services: docker
|
||||
sudo: required
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libssl-dev
|
||||
|
||||
after_success: |
|
||||
if [ "$TARGET" = x86_64-unknown-linux-gnu -a "$TRAVIS_RUST_VERSION" = stable ]; then
|
||||
bash <(curl https://raw.githubusercontent.com/xd009642/tarpaulin/master/travis-install.sh)
|
||||
cargo tarpaulin --out Xml
|
||||
bash <(curl -s https://codecov.io/bash)
|
||||
fi
|
||||
|
||||
# TODO Rust builds on stable by default, this can be
|
||||
# overridden on a case by case basis down below.
|
||||
|
||||
env:
|
||||
global:
|
||||
# TODO Update this to match the name of your project.
|
||||
- CRATE_NAME=platform-info
|
||||
|
||||
matrix:
|
||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
||||
# don't need
|
||||
include:
|
||||
# Android
|
||||
- env: TARGET=aarch64-linux-android DISABLE_TESTS=1
|
||||
- env: TARGET=arm-linux-androideabi DISABLE_TESTS=1
|
||||
- env: TARGET=armv7-linux-androideabi DISABLE_TESTS=1
|
||||
- env: TARGET=i686-linux-android DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-linux-android DISABLE_TESTS=1
|
||||
|
||||
# iOS
|
||||
- env: TARGET=aarch64-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=armv7-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=armv7s-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=i386-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
- env: TARGET=x86_64-apple-ios DISABLE_TESTS=1
|
||||
os: osx
|
||||
|
||||
# Linux
|
||||
- env: TARGET=aarch64-unknown-linux-gnu
|
||||
- env: TARGET=arm-unknown-linux-gnueabi
|
||||
- env: TARGET=armv7-unknown-linux-gnueabihf
|
||||
- env: TARGET=i686-unknown-linux-gnu
|
||||
- env: TARGET=i686-unknown-linux-musl
|
||||
- env: TARGET=mips-unknown-linux-gnu
|
||||
- env: TARGET=mips64-unknown-linux-gnuabi64
|
||||
- env: TARGET=mips64el-unknown-linux-gnuabi64
|
||||
- env: TARGET=mipsel-unknown-linux-gnu
|
||||
- env: TARGET=powerpc-unknown-linux-gnu
|
||||
- env: TARGET=powerpc64-unknown-linux-gnu
|
||||
- env: TARGET=powerpc64le-unknown-linux-gnu
|
||||
- env: TARGET=s390x-unknown-linux-gnu DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
- env: TARGET=x86_64-unknown-linux-musl
|
||||
|
||||
# OSX
|
||||
- env: TARGET=i686-apple-darwin
|
||||
os: osx
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
|
||||
# *BSD
|
||||
- env: TARGET=i686-unknown-freebsd DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-freebsd DISABLE_TESTS=1
|
||||
- env: TARGET=x86_64-unknown-netbsd DISABLE_TESTS=1
|
||||
|
||||
# Windows
|
||||
- env: TARGET=x86_64-pc-windows-gnu
|
||||
|
||||
# Redox
|
||||
- env: TARGET=x86_64-unknown-redox CC=x86_64-unknown-redox-gcc REDOX=1 DISABLE_TESTS=1
|
||||
|
||||
# Bare metal
|
||||
# These targets don't support std and as such are likely not suitable for
|
||||
# most crates.
|
||||
# - env: TARGET=thumbv6m-none-eabi
|
||||
# - env: TARGET=thumbv7em-none-eabi
|
||||
# - env: TARGET=thumbv7em-none-eabihf
|
||||
# - env: TARGET=thumbv7m-none-eabi
|
||||
|
||||
# Testing other channels
|
||||
- env: TARGET=x86_64-unknown-linux-gnu
|
||||
rust: nightly
|
||||
- env: TARGET=x86_64-apple-darwin
|
||||
os: osx
|
||||
rust: nightly
|
||||
|
||||
before_install:
|
||||
- set -e
|
||||
- rustup self update
|
||||
- if [ $REDOX ]; then ./.travis/redox-toolchain.sh; fi
|
||||
|
||||
install:
|
||||
- sh ci/install.sh
|
||||
- source ~/.cargo/env || true
|
||||
|
||||
script:
|
||||
- bash ci/script.sh
|
||||
|
||||
after_script: set +e
|
||||
|
||||
before_deploy:
|
||||
- sh ci/before_deploy.sh
|
||||
|
||||
deploy:
|
||||
# TODO update `api_key.secure`
|
||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
||||
# - Encrypt it: `travis encrypt 0123456789012345678901234567890123456789
|
||||
# - Paste the output down here
|
||||
api_key:
|
||||
secure: A9v3PIzQQ4U08OHFmDPQzNXbNHEb7YHyLXCvMF+dXFuNSvhUNlmQYykxqUf3dvikhJL2/bsZ14umm7ni7fQh0tGwJ4+lPpNzYAcweGgNXnWvjTpY6ovuRbr3gs4/srkyxp/GBDmSW5L8wFN3hKCB+Lm0YnIPB9IA2afP8a30+8VTXT9nv7pNqGny4ilN41ycr4DZi3sQoXdbruy7ClN7gsWW/GUiudBccHVIjmTapOFKLwZHODaUl/1/RDWQzh+i+17e1ivXuJPktDSrqmHPTZ15OjklnHKd6t179ry6VkGRg4R/R/YukVIqGzeaXGWAwdAQ5gE8cjGZghJLVi2jkDBJ85z8MvT+zLZLyliiuhLc/X8y7mkE1n0FKFtXXzFVt0l7V1LaEKbIbiV6XX3jsir4qgkqWjPHBZqO5mkGNFS16Dmt30/ZtEPAzXiINFXbWuWrpQ/LZ4NSto8IMrRTcoyDbAga/KYxJiNIeVuCe1E9dbytDM7K0GLtxJTul/WnnSeI6r//EFyC4bxYjyHhCXaag4q14KM+ak4rB0QgxsYzyGuh2MqyCoVj8YJLjLdKnL/SV7W7LPD40xlxvI6VCYTVi2ILHwL6vCxpukXYteX0c5IAIWkISDKu6nNBEgmCHXXPSqYSrgE5g7/QoCQHI8++nR8iKe0s7TWxZRydby8=
|
||||
file_glob: true
|
||||
file: $CRATE_NAME-$TRAVIS_TAG-$TARGET.*
|
||||
on:
|
||||
# TODO Here you can pick which targets will generate binary releases
|
||||
# In this example, there are some targets that are tested using the stable
|
||||
# and nightly channels. This condition makes sure there is only one release
|
||||
# for such targets and that's generated using the stable channel
|
||||
condition: $TRAVIS_RUST_VERSION = stable
|
||||
tags: true
|
||||
provider: releases
|
||||
skip_cleanup: true
|
||||
|
||||
cache: cargo
|
||||
before_cache:
|
||||
# Travis can't cache files that are not readable by "others"
|
||||
- chmod -R a+r $HOME/.cargo
|
||||
|
||||
branches:
|
||||
only:
|
||||
# release tags
|
||||
- /^v\d+\.\d+\.\d+.*$/
|
||||
- master
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: never
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
rustup target add x86_64-unknown-redox
|
||||
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys AA12E97F0881517F
|
||||
sudo add-apt-repository 'deb https://static.redox-os.org/toolchain/apt /'
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y x86-64-unknown-redox-gcc
|
||||
+1
-1
@@ -5,4 +5,4 @@ authors = ["Alex Lyon <arcterus@mail.com>"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
winapi = { version = "0.3", features = ["sysinfoapi"] }
|
||||
winapi = { version = "0.3", features = ["libloaderapi", "sysinfoapi", "winbase", "winver"] }
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
# Based on the "trust" template v0.1.2
|
||||
# https://github.com/japaric/trust/tree/v0.1.2
|
||||
|
||||
environment:
|
||||
global:
|
||||
# TODO This is the Rust channel that build jobs will use by default but can be
|
||||
# overridden on a case by case basis down below
|
||||
RUST_VERSION: stable
|
||||
|
||||
# TODO Update this to match the name of your project.
|
||||
CRATE_NAME: platform-info
|
||||
|
||||
# TODO These are all the build jobs. Adjust as necessary. Comment out what you
|
||||
# don't need
|
||||
matrix:
|
||||
# MinGW
|
||||
- TARGET: i686-pc-windows-gnu
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
|
||||
# MSVC
|
||||
- TARGET: i686-pc-windows-msvc
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
|
||||
# Testing other channels
|
||||
- TARGET: x86_64-pc-windows-gnu
|
||||
RUST_VERSION: nightly
|
||||
- TARGET: x86_64-pc-windows-msvc
|
||||
RUST_VERSION: nightly
|
||||
|
||||
install:
|
||||
- ps: >-
|
||||
If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') {
|
||||
$Env:PATH += ';C:\msys64\mingw64\bin'
|
||||
} ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') {
|
||||
$Env:PATH += ';C:\msys64\mingw32\bin'
|
||||
}
|
||||
- curl -sSf -o rustup-init.exe https://win.rustup.rs/
|
||||
- rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION%
|
||||
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||
- rustc -Vv
|
||||
- cargo -V
|
||||
|
||||
# TODO This is the "test phase", tweak it as you see fit
|
||||
test_script:
|
||||
# we don't run the "test phase" when doing deploys
|
||||
- if [%APPVEYOR_REPO_TAG%]==[false] (
|
||||
cargo build --target %TARGET% &&
|
||||
cargo build --target %TARGET% --release &&
|
||||
cargo test --target %TARGET% &&
|
||||
cargo test --target %TARGET% --release
|
||||
)
|
||||
|
||||
before_deploy:
|
||||
# TODO Update this to build the artifacts that matter to you
|
||||
- cargo rustc --target %TARGET% --release -- -C lto
|
||||
- ps: ci\before_deploy.ps1
|
||||
|
||||
deploy:
|
||||
artifact: /.*\.zip/
|
||||
# TODO update `auth_token.secure`
|
||||
# - Create a `public_repo` GitHub token. Go to: https://github.com/settings/tokens/new
|
||||
# - Encrypt it. Go to https://ci.appveyor.com/tools/encrypt
|
||||
# - Paste the output down here
|
||||
auth_token:
|
||||
secure: Xv7lZVmUMWpCKov9dU4t3bl4hhHob31MqgX16HOeJzKiTbHEstWaUc8seGkvwJXT
|
||||
description: ''
|
||||
on:
|
||||
# TODO Here you can pick which targets will generate binary releases
|
||||
# In this example, there are some targets that are tested using the stable
|
||||
# and nightly channels. This condition makes sure there is only one release
|
||||
# for such targets and that's generated using the stable channel
|
||||
RUST_VERSION: stable
|
||||
appveyor_repo_tag: true
|
||||
provider: GitHub
|
||||
|
||||
cache:
|
||||
- C:\Users\appveyor\.cargo\registry
|
||||
- target
|
||||
|
||||
branches:
|
||||
only:
|
||||
# Release tags
|
||||
- /^v\d+\.\d+\.\d+.*$/
|
||||
- master
|
||||
|
||||
notifications:
|
||||
- provider: Email
|
||||
on_build_success: false
|
||||
|
||||
# Building is done in the test phase, so we disable Appveyor's build phase.
|
||||
build: false
|
||||
@@ -0,0 +1,23 @@
|
||||
# This script takes care of packaging the build artifacts that will go in the
|
||||
# release zipfile
|
||||
|
||||
$SRC_DIR = $PWD.Path
|
||||
$STAGE = [System.Guid]::NewGuid().ToString()
|
||||
|
||||
Set-Location $ENV:Temp
|
||||
New-Item -Type Directory -Name $STAGE
|
||||
Set-Location $STAGE
|
||||
|
||||
$ZIP = "$SRC_DIR\$($Env:CRATE_NAME)-$($Env:APPVEYOR_REPO_TAG_NAME)-$($Env:TARGET).zip"
|
||||
|
||||
# TODO Update this to package the right artifacts
|
||||
Copy-Item "$SRC_DIR\target\$($Env:TARGET)\release\libplatform_info.rlib" '.\'
|
||||
|
||||
7z a "$ZIP" *
|
||||
|
||||
Push-AppveyorArtifact "$ZIP"
|
||||
|
||||
Remove-Item *.* -Force
|
||||
Set-Location ..
|
||||
Remove-Item $STAGE
|
||||
Set-Location $SRC_DIR
|
||||
@@ -0,0 +1,33 @@
|
||||
# This script takes care of building your crate and packaging it for release
|
||||
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
local src=$(pwd) \
|
||||
stage=
|
||||
|
||||
case $TRAVIS_OS_NAME in
|
||||
linux)
|
||||
stage=$(mktemp -d)
|
||||
;;
|
||||
osx)
|
||||
stage=$(mktemp -d -t tmp)
|
||||
;;
|
||||
esac
|
||||
|
||||
test -f Cargo.lock || cargo generate-lockfile
|
||||
|
||||
# TODO Update this to build the artifacts that matter to you
|
||||
cross rustc --target $TARGET --release -- -C lto
|
||||
|
||||
# TODO Update this to package the right artifacts
|
||||
cp target/$TARGET/release/libplatform_info.rlib $stage/
|
||||
|
||||
cd $stage
|
||||
tar czf $src/$CRATE_NAME-$TRAVIS_TAG-$TARGET.tar.gz *
|
||||
cd $src
|
||||
|
||||
rm -rf $stage
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,47 @@
|
||||
set -ex
|
||||
|
||||
main() {
|
||||
local target=
|
||||
if [ $TRAVIS_OS_NAME = linux ]; then
|
||||
target=x86_64-unknown-linux-musl
|
||||
sort=sort
|
||||
else
|
||||
target=x86_64-apple-darwin
|
||||
sort=gsort # for `sort --sort-version`, from brew's coreutils.
|
||||
fi
|
||||
|
||||
# Builds for iOS are done on OSX, but require the specific target to be
|
||||
# installed.
|
||||
case $TARGET in
|
||||
aarch64-apple-ios)
|
||||
rustup target install aarch64-apple-ios
|
||||
;;
|
||||
armv7-apple-ios)
|
||||
rustup target install armv7-apple-ios
|
||||
;;
|
||||
armv7s-apple-ios)
|
||||
rustup target install armv7s-apple-ios
|
||||
;;
|
||||
i386-apple-ios)
|
||||
rustup target install i386-apple-ios
|
||||
;;
|
||||
x86_64-apple-ios)
|
||||
rustup target install x86_64-apple-ios
|
||||
;;
|
||||
esac
|
||||
|
||||
# This fetches latest stable release
|
||||
local tag=$(git ls-remote --tags --refs --exit-code https://github.com/japaric/cross \
|
||||
| cut -d/ -f3 \
|
||||
| grep -E '^v[0.1.0-9.]+$' \
|
||||
| $sort --version-sort \
|
||||
| tail -n1)
|
||||
curl -LSfs https://japaric.github.io/trust/install.sh | \
|
||||
sh -s -- \
|
||||
--force \
|
||||
--git japaric/cross \
|
||||
--tag $tag \
|
||||
--target $target
|
||||
}
|
||||
|
||||
main
|
||||
@@ -0,0 +1,21 @@
|
||||
# This script takes care of testing your crate
|
||||
|
||||
set -ex
|
||||
|
||||
# TODO This is the "test phase", tweak it as you see fit
|
||||
main() {
|
||||
cross build --target $TARGET
|
||||
cross build --target $TARGET --release
|
||||
|
||||
if [ ! -z $DISABLE_TESTS ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
cross test --target $TARGET
|
||||
cross test --target $TARGET --release
|
||||
}
|
||||
|
||||
# we don't run the "test phase" when doing deploys
|
||||
if [ -z $TRAVIS_TAG ]; then
|
||||
main
|
||||
fi
|
||||
+17
-10
@@ -1,22 +1,29 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE file
|
||||
// that was distributed with this source code.
|
||||
//
|
||||
|
||||
pub use platform::*;
|
||||
pub use self::sys::*;
|
||||
|
||||
mod platform;
|
||||
use std::borrow::Cow;
|
||||
|
||||
//pub trait Uname
|
||||
#[cfg(unix)]
|
||||
#[path = "unix.rs"]
|
||||
mod sys;
|
||||
#[cfg(windows)]
|
||||
#[path = "windows.rs"]
|
||||
mod sys;
|
||||
#[cfg(target_os = "redox")]
|
||||
#[path = "redox.rs"]
|
||||
mod sys;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
pub trait Uname {
|
||||
fn sysname(&self) -> Cow<str>;
|
||||
fn nodename(&self) -> Cow<str>;
|
||||
fn release(&self) -> Cow<str>;
|
||||
fn version(&self) -> Cow<str>;
|
||||
fn machine(&self) -> Cow<str>;
|
||||
}
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE file
|
||||
// that was distributed with this source code.
|
||||
//
|
||||
|
||||
#[cfg(unix)]
|
||||
pub use self::unix::*;
|
||||
#[cfg(windows)]
|
||||
pub use self::windows::*;
|
||||
#[cfg(target_os = "redox")]
|
||||
pub use self::redox::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix;
|
||||
#[cfg(windows)]
|
||||
mod windows;
|
||||
#[cfg(target_os = "redox")]
|
||||
mod redox;
|
||||
@@ -1,41 +0,0 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE file
|
||||
// that was distributed with this source code.
|
||||
//
|
||||
|
||||
extern crate winapi;
|
||||
|
||||
use self::winapi::um::sysinfoapi::{SYSTEM_INFO, GetSystemInfo};
|
||||
use self::winapi::um::winnt::*;
|
||||
use std::mem;
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
|
||||
pub struct Uname {
|
||||
inner: SYSTEM_INFO
|
||||
}
|
||||
|
||||
impl Uname {
|
||||
pub fn new() -> io::Result<Uname> {
|
||||
unsafe {
|
||||
let mut info = mem::uninitialized();
|
||||
GetSystemInfo(&mut info);
|
||||
Ok(Uname { inner: info })
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: need to implement more architectures (e.g. ARM)
|
||||
pub fn machine(&self) -> Cow<str> {
|
||||
let arch = unsafe {
|
||||
match self.inner.u.s().wProcessorArchitecture {
|
||||
PROCESSOR_ARCHITECTURE_AMD64 => "x86_64",
|
||||
PROCESSOR_ARCHITECTURE_INTEL => "x86",
|
||||
_ => unimplemented!()
|
||||
}
|
||||
};
|
||||
Cow::from(arch)
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,12 @@
|
||||
// that was distributed with this source code.
|
||||
//
|
||||
|
||||
use super::Uname;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{self, Read};
|
||||
use std::fs::File;
|
||||
|
||||
pub struct Uname {
|
||||
pub struct PlatformInfo {
|
||||
kernel_name: String,
|
||||
nodename: String,
|
||||
kernel_release: String,
|
||||
@@ -18,8 +19,8 @@ pub struct Uname {
|
||||
machine: String
|
||||
}
|
||||
|
||||
impl Uname {
|
||||
pub fn new() -> io::Result<Uname> {
|
||||
impl PlatformInfo {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
let mut inner = Box::new(String::new());
|
||||
File::open("sys:uname")?.read_to_string(&mut inner)?;
|
||||
|
||||
@@ -32,7 +33,7 @@ impl Uname {
|
||||
let machine = lines.next().unwrap();
|
||||
|
||||
// FIXME: don't actually duplicate the data as doing so is wasteful
|
||||
Ok(Uname {
|
||||
Ok(Self {
|
||||
kernel_name: kernel_name.to_owned(),
|
||||
nodename: nodename.to_owned(),
|
||||
kernel_release: kernel_release.to_owned(),
|
||||
@@ -40,24 +41,26 @@ impl Uname {
|
||||
machine: machine.to_owned()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sysname(&self) -> Cow<str> {
|
||||
impl Uname for PlatformInfo {
|
||||
fn sysname(&self) -> Cow<str> {
|
||||
Cow::from(self.kernel_name.as_str())
|
||||
}
|
||||
|
||||
pub fn nodename(&self) -> Cow<str> {
|
||||
fn nodename(&self) -> Cow<str> {
|
||||
Cow::from(self.nodename.as_str())
|
||||
}
|
||||
|
||||
pub fn release(&self) -> Cow<str> {
|
||||
fn release(&self) -> Cow<str> {
|
||||
Cow::from(self.kernel_release.as_str())
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Cow<str> {
|
||||
fn version(&self) -> Cow<str> {
|
||||
Cow::from(self.kernel_version.as_str())
|
||||
}
|
||||
|
||||
pub fn machine(&self) -> Cow<str> {
|
||||
fn machine(&self) -> Cow<str> {
|
||||
Cow::from(self.machine.as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
extern crate libc;
|
||||
|
||||
use self::libc::{uname, utsname};
|
||||
use super::Uname;
|
||||
use std::mem;
|
||||
use std::ffi::CStr;
|
||||
use std::borrow::Cow;
|
||||
@@ -21,39 +22,41 @@ macro_rules! cstr2cow {
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Uname {
|
||||
pub struct PlatformInfo {
|
||||
inner: utsname,
|
||||
}
|
||||
|
||||
impl Uname {
|
||||
impl PlatformInfo {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
unsafe {
|
||||
let mut uts: utsname = mem::uninitialized();
|
||||
if uname(&mut uts) == 0 {
|
||||
Ok(Uname { inner: uts })
|
||||
Ok(Self { inner: uts })
|
||||
} else {
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn sysname(&self) -> Cow<str> {
|
||||
impl Uname for PlatformInfo {
|
||||
fn sysname(&self) -> Cow<str> {
|
||||
cstr2cow!(self.inner.sysname)
|
||||
}
|
||||
|
||||
pub fn nodename(&self) -> Cow<str> {
|
||||
fn nodename(&self) -> Cow<str> {
|
||||
cstr2cow!(self.inner.nodename)
|
||||
}
|
||||
|
||||
pub fn release(&self) -> Cow<str> {
|
||||
fn release(&self) -> Cow<str> {
|
||||
cstr2cow!(self.inner.release)
|
||||
}
|
||||
|
||||
pub fn version(&self) -> Cow<str> {
|
||||
fn version(&self) -> Cow<str> {
|
||||
cstr2cow!(self.inner.version)
|
||||
}
|
||||
|
||||
pub fn machine(&self) -> Cow<str> {
|
||||
fn machine(&self) -> Cow<str> {
|
||||
cstr2cow!(self.inner.machine)
|
||||
}
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// (c) Alex Lyon <arcterus@mail.com>
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE file
|
||||
// that was distributed with this source code.
|
||||
//
|
||||
|
||||
extern crate winapi;
|
||||
|
||||
use self::winapi::um::libloaderapi::*;
|
||||
use self::winapi::um::sysinfoapi::*;
|
||||
use self::winapi::um::winbase::*;
|
||||
use self::winapi::um::winnt::*;
|
||||
use self::winapi::um::winver::*;
|
||||
use self::winapi::shared::ntstatus::*;
|
||||
use self::winapi::shared::ntdef::NTSTATUS;
|
||||
use self::winapi::shared::minwindef::*;
|
||||
use super::Uname;
|
||||
use std::ffi::{CStr, OsStr, OsString};
|
||||
use std::mem;
|
||||
use std::borrow::Cow;
|
||||
use std::io;
|
||||
use std::iter;
|
||||
use std::os::windows::ffi::{OsStrExt, OsStringExt};
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
struct VS_FIXEDFILEINFO {
|
||||
dwSignature: DWORD,
|
||||
dwStrucVersion: DWORD,
|
||||
dwFileVersionMS: DWORD,
|
||||
dwFileVersionLS: DWORD,
|
||||
dwProductVersionMS: DWORD,
|
||||
dwProductVersionLS: DWORD,
|
||||
dwFileFlagsMask: DWORD,
|
||||
dwFileFlags: DWORD,
|
||||
dwFileOS: DWORD,
|
||||
dwFileType: DWORD,
|
||||
dwFileSubtype: DWORD,
|
||||
dwFileDateMS: DWORD,
|
||||
dwFileDateLS: DWORD,
|
||||
}
|
||||
|
||||
pub struct PlatformInfo {
|
||||
sysinfo: SYSTEM_INFO,
|
||||
nodename: String,
|
||||
release: String,
|
||||
version: String,
|
||||
}
|
||||
|
||||
impl PlatformInfo {
|
||||
pub fn new() -> io::Result<Self> {
|
||||
unsafe {
|
||||
let mut sysinfo = mem::uninitialized();
|
||||
|
||||
GetNativeSystemInfo(&mut sysinfo);
|
||||
|
||||
let (version, release) = Self::version_info()?;
|
||||
let nodename = Self::computer_name()?;
|
||||
|
||||
Ok(Self {
|
||||
sysinfo: sysinfo,
|
||||
nodename: nodename,
|
||||
version: version,
|
||||
release: release
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn computer_name() -> io::Result<String> {
|
||||
let mut size = 0;
|
||||
unsafe {
|
||||
// NOTE: shouldn't need to check the error because, on error, the required size will be
|
||||
// stored in the size variable
|
||||
// XXX: verify that ComputerNameDnsHostname is the best option
|
||||
GetComputerNameExW(ComputerNameDnsHostname, ptr::null_mut(), &mut size);
|
||||
}
|
||||
let mut data = Vec::with_capacity(size as usize);
|
||||
unsafe {
|
||||
// we subtract one from the size because the returned size includes the null terminator
|
||||
data.set_len(size as usize - 1);
|
||||
|
||||
if GetComputerNameExW(ComputerNameDnsHostname, data.as_mut_ptr(), &mut size) != 0 {
|
||||
Ok(String::from_utf16_lossy(&data))
|
||||
} else {
|
||||
// XXX: should this error or just return localhost?
|
||||
Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: the only reason any of this has to be done is Microsoft deprecated GetVersionEx() and
|
||||
// it is now basically useless for us on Windows 8.1 and Windows 10
|
||||
unsafe fn version_info() -> io::Result<(String, String)> {
|
||||
let dll_wide: Vec<WCHAR> = OsStr::new("ntdll.dll").encode_wide().chain(iter::once(0)).collect();
|
||||
let module = GetModuleHandleW(dll_wide.as_ptr());
|
||||
if !module.is_null() {
|
||||
let funcname = CStr::from_bytes_with_nul_unchecked(b"RtlGetVersion\0");
|
||||
let func = GetProcAddress(module, funcname.as_ptr());
|
||||
if !func.is_null() {
|
||||
let func: extern "stdcall" fn(*mut RTL_OSVERSIONINFOEXW) -> NTSTATUS = mem::transmute(func as *const ());
|
||||
|
||||
let mut osinfo: RTL_OSVERSIONINFOEXW = mem::zeroed();
|
||||
osinfo.dwOSVersionInfoSize = mem::size_of::<RTL_OSVERSIONINFOEXW>() as _;
|
||||
|
||||
if func(&mut osinfo) == STATUS_SUCCESS {
|
||||
let version = String::from_utf16_lossy(&osinfo.szCSDVersion.split(|&v| v == 0).next().unwrap());
|
||||
let release = Self::determine_release(osinfo.dwMajorVersion, osinfo.dwMinorVersion, osinfo.wProductType, osinfo.wSuiteMask);
|
||||
|
||||
return Ok((version, release));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// as a last resort, try to get the relevant info by loading the version info from a system
|
||||
// file (specifically Kernel32.dll)
|
||||
Self::version_info_from_file()
|
||||
}
|
||||
|
||||
fn version_info_from_file() -> io::Result<(String, String)> {
|
||||
use self::winapi::um::sysinfoapi;
|
||||
|
||||
let pathbuf = Self::get_kernel32_path()?;
|
||||
|
||||
let file_info = Self::get_file_version_info(pathbuf)?;
|
||||
let (major, minor) = Self::query_version_info(file_info)?;
|
||||
|
||||
let mut info: OSVERSIONINFOEXW = unsafe { mem::uninitialized() };
|
||||
info.wSuiteMask = VER_SUITE_WH_SERVER as WORD;
|
||||
info.wProductType = VER_NT_WORKSTATION;
|
||||
|
||||
let mask = unsafe { sysinfoapi::VerSetConditionMask(0, VER_SUITENAME, VER_EQUAL) };
|
||||
let suite_mask = if unsafe { VerifyVersionInfoW(&mut info, VER_SUITENAME, mask) } != 0 {
|
||||
VER_SUITE_WH_SERVER as USHORT
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let mask = unsafe { sysinfoapi::VerSetConditionMask(0, VER_PRODUCT_TYPE, VER_EQUAL) };
|
||||
let product_type = if unsafe { VerifyVersionInfoW(&mut info, VER_PRODUCT_TYPE, mask) } != 0 {
|
||||
VER_NT_WORKSTATION
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
Ok((String::new(), Self::determine_release(major, minor, product_type, suite_mask)))
|
||||
}
|
||||
|
||||
fn get_kernel32_path() -> io::Result<PathBuf> {
|
||||
let file = OsStr::new("Kernel32.dll");
|
||||
// the "- 1" is to account for the path separator
|
||||
let buf_capacity = MAX_PATH - file.len() - 1;
|
||||
|
||||
let mut buffer = Vec::with_capacity(buf_capacity);
|
||||
let buf_size = unsafe { GetSystemDirectoryW(buffer.as_mut_ptr(), buf_capacity as UINT) };
|
||||
|
||||
if buf_size >= buf_capacity as UINT || buf_size == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
unsafe {
|
||||
buffer.set_len(buf_size as usize);
|
||||
}
|
||||
|
||||
let mut pathbuf = PathBuf::from(OsString::from_wide(&buffer));
|
||||
pathbuf.push(file);
|
||||
|
||||
Ok(pathbuf)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_file_version_info(path: PathBuf) -> io::Result<Vec<u8>> {
|
||||
let path_wide: Vec<_> = path.as_os_str().encode_wide().chain(iter::once(0)).collect();
|
||||
let fver_size = unsafe { GetFileVersionInfoSizeW(path_wide.as_ptr(), ptr::null_mut()) };
|
||||
|
||||
if fver_size == 0 {
|
||||
return Err(io::Error::last_os_error());
|
||||
}
|
||||
|
||||
let mut buffer = Vec::with_capacity(fver_size as usize);
|
||||
if unsafe { GetFileVersionInfoW(path_wide.as_ptr(), 0, fver_size, buffer.as_mut_ptr() as *mut _) } == 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
unsafe {
|
||||
buffer.set_len(fver_size as usize);
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
}
|
||||
|
||||
fn query_version_info(buffer: Vec<u8>) -> io::Result<(ULONG, ULONG)> {
|
||||
let mut block_size = 0;
|
||||
let mut block = unsafe { mem::uninitialized() };
|
||||
|
||||
let sub_block: Vec<_> = OsStr::new("\\").encode_wide().chain(iter::once(0)).collect();
|
||||
if unsafe { VerQueryValueW(buffer.as_ptr() as *const _, sub_block.as_ptr(), &mut block, &mut block_size) == 0 } {
|
||||
if block_size < mem::size_of::<VS_FIXEDFILEINFO>() as UINT {
|
||||
return Err(io::Error::last_os_error())
|
||||
}
|
||||
}
|
||||
|
||||
let info = unsafe { &*(block as *const VS_FIXEDFILEINFO) };
|
||||
|
||||
Ok((HIWORD(info.dwProductVersionMS) as _, LOWORD(info.dwProductVersionMS) as _))
|
||||
}
|
||||
|
||||
fn determine_release(major: ULONG, minor: ULONG, product_type: UCHAR, suite_mask: USHORT) -> String {
|
||||
let mut name = match major {
|
||||
5 => match minor {
|
||||
0 => "Windows 2000",
|
||||
1 => "Windows XP",
|
||||
2 if product_type == VER_NT_WORKSTATION => "Windows XP Professional x64 Edition",
|
||||
2 if suite_mask as UINT == VER_SUITE_WH_SERVER => "Windows Home Server",
|
||||
2 => "Windows Server 2003",
|
||||
_ => ""
|
||||
}
|
||||
6 => match minor {
|
||||
0 if product_type == VER_NT_WORKSTATION => "Windows Vista",
|
||||
0 => "Windows Server 2008",
|
||||
1 if product_type != VER_NT_WORKSTATION => "Windows Server 2008 R2",
|
||||
1 => "Windows 7",
|
||||
2 if product_type != VER_NT_WORKSTATION => "Windows Server 2012",
|
||||
2 => "Windows 8",
|
||||
3 if product_type != VER_NT_WORKSTATION => "Windows Server 2012 R2",
|
||||
3 => "Windows 8.1",
|
||||
_ => ""
|
||||
}
|
||||
10 => match minor {
|
||||
0 if product_type != VER_NT_WORKSTATION => "Windows Server 2016",
|
||||
_ => ""
|
||||
}
|
||||
_ => ""
|
||||
};
|
||||
|
||||
// we're doing this down here so we don't have to copy this into multiple branches
|
||||
if name.len() == 0 {
|
||||
name = if product_type == VER_NT_WORKSTATION {
|
||||
"Windows"
|
||||
} else {
|
||||
"Windows Server"
|
||||
};
|
||||
}
|
||||
|
||||
format!("{} {}.{}", name, major, minor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Uname for PlatformInfo {
|
||||
fn sysname(&self) -> Cow<str> {
|
||||
// TODO: report if using MinGW instead of MSVC
|
||||
|
||||
// XXX: if Rust ever works on Windows CE and winapi has the VER_PLATFORM_WIN32_CE
|
||||
// constant, we should probably check for that
|
||||
Cow::from("WindowsNT")
|
||||
}
|
||||
|
||||
fn nodename(&self) -> Cow<str> {
|
||||
Cow::from(self.nodename.as_str())
|
||||
}
|
||||
|
||||
// FIXME: definitely wrong
|
||||
fn release(&self) -> Cow<str> {
|
||||
Cow::from(self.release.as_str())
|
||||
}
|
||||
|
||||
// FIXME: this is prob wrong
|
||||
fn version(&self) -> Cow<str> {
|
||||
Cow::from(self.version.as_str())
|
||||
}
|
||||
|
||||
fn machine(&self) -> Cow<str> {
|
||||
let arch = unsafe { self.sysinfo.u.s().wProcessorArchitecture };
|
||||
|
||||
let arch_str = match arch {
|
||||
PROCESSOR_ARCHITECTURE_AMD64 => "x86_64",
|
||||
PROCESSOR_ARCHITECTURE_INTEL => {
|
||||
match self.sysinfo.wProcessorLevel {
|
||||
4 => "i486",
|
||||
5 => "i586",
|
||||
6 => "i686",
|
||||
_ => "i386"
|
||||
}
|
||||
}
|
||||
PROCESSOR_ARCHITECTURE_IA64 => "ia64",
|
||||
// FIXME: not sure if this is wrong because I think uname usually returns stuff like
|
||||
// armv7l on Linux, but can't find a way to figure that out on Windows
|
||||
PROCESSOR_ARCHITECTURE_ARM => "arm",
|
||||
// XXX: I believe this is correct for GNU compat, but differs from LLVM? Like the ARM
|
||||
// branch above, I'm not really sure about this one either
|
||||
PROCESSOR_ARCHITECTURE_ARM64 => "aarch64",
|
||||
PROCESSOR_ARCHITECTURE_MIPS => "mips",
|
||||
PROCESSOR_ARCHITECTURE_PPC => "powerpc",
|
||||
PROCESSOR_ARCHITECTURE_ALPHA | PROCESSOR_ARCHITECTURE_ALPHA64 => "alpha",
|
||||
// FIXME: I don't know anything about this architecture, so this may be incorrect
|
||||
PROCESSOR_ARCHITECTURE_SHX => "sh",
|
||||
_ => "unknown"
|
||||
};
|
||||
|
||||
Cow::from(arch_str)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sysname() {
|
||||
assert_eq!(PlatformInfo::new().unwrap().sysname(), "WindowsNT");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_machine() {
|
||||
let target = if cfg!(target_arch = "x86_64") {
|
||||
vec!["x86_64"]
|
||||
} else if cfg!(target_arch = "x86") {
|
||||
vec!["i386", "i486", "i586", "i686"]
|
||||
} else if cfg!(target_arch = "arm") {
|
||||
vec!["arm"]
|
||||
} else if cfg!(target_arch = "aarch64") {
|
||||
// NOTE: keeping both of these until the correct behavior is sorted out
|
||||
vec!["arm64", "aarch64"]
|
||||
} else if cfg!(target_arch = "powerpc") {
|
||||
vec!["powerpc"]
|
||||
} else if cfg!(target_arch = "mips") {
|
||||
vec!["mips"]
|
||||
} else {
|
||||
// NOTE: the other architecture are currently not valid targets for Rust (in fact, I am
|
||||
// almost certain some of these are not even valid targets for the Windows build)
|
||||
vec!["unknown"]
|
||||
};
|
||||
|
||||
assert!(target.contains(&&*PlatformInfo::new().unwrap().machine()));
|
||||
}
|
||||
|
||||
// TODO: figure out a way to test these
|
||||
/*
|
||||
#[test]
|
||||
fn test_nodename() {
|
||||
let info = PlatformInfo::new().unwrap();
|
||||
panic!("{}", info.nodename());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_version() {
|
||||
let info = PlatformInfo::new().unwrap();
|
||||
panic!("{}", info.version());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_release() {
|
||||
let info = PlatformInfo::new().unwrap();
|
||||
panic!("{}", info.release());
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user