ardaku / whoami

Rust crate to get the current user and environment.
Apache License 2.0
195 stars 31 forks source link

Support getting OS arch(32-bit or 64-bit) #25

Closed abdullah2993 closed 1 year ago

abdullah2993 commented 3 years ago

Is your feature request related to a problem? Please describe. No. It would be a nice to have feature.

Describe the solution you'd like Ability to get the arch of the OS.

Describe alternatives you've considered There is a crate available for that https://crates.io/crates/bitness crate

Additional context Although there are crates available that does the same thing but it would be nice to have it included in whoami

AldaronLau commented 3 years ago

@abdullah2993 This seems like a good feature to add. Probably in the form of an arch() function that returns a String corresponding to the architecture, in rustup's architecture format, rather than from the system's API:

Either that, or create a non exhaustive enum of all the possible architectures, which might be better because then it can implement a method to get the number of bits for the architecture.

SteveLauC commented 1 year ago

Friendly ping @AldaronLau.

I would like to give this a try, any tips on how to implement this?

We can get those constants through std::env::consts::ARCH at compile time, but it is flawed. Since this information is generated at compile time, if we have a binary built for platform A, then we run it on platform B (e.g., a binary for x86 can be run on x86-64 platforms), then the result would simply be wrong.

AldaronLau commented 1 year ago

@SteveLauC Thanks for your interest! It will have to be implemented separately for each platform calling into system APIs.

A simple solution for Linux would be to execute the lscpu command and parse the first line of output (which I believe is transformed from the data in /proc/cpuinfo, although I'm not quite sure how - which whoami could do itself instead of relying on the external command):

Architecture:            x86_64

On WebAssembly, this information would not be exposed, so it's ok to use compile time checks to get the "architecture".

MacOS, BSD and Windows will need their own separate implementations calling into the respective system APIs (requires some research).

Researching and implementing this feature isn't high priority on my todo list, so help would be greatly appreciated! Also, since there are multiple platforms, I wouldn't expect them to be all done in one PR (feel free to break it up if you decide to implement it).

As for the exposed API, I'm thinking something along the lines of:

pub enum Arch {
    /// aarch64
    Aarch64,
    /// i686
    I686,
    /// x86_64
    X86,
    // Etc.
}

pub enum PointerSize {
    Bits32,
    Bits64,
}

impl Arch {
    pub fn bits() -> PointerSize {
        todo!()
    }
}

pub fn arch() -> Arch {
    // Default for unsupported platforms would fallback to converting from `std::env::consts::ARCH`
}

I think either way for Linux (the lscpu command or parsing /proc/cpuinfo) would be fine initially, although I would like to move the whoami crate away from depending on external commands.

SteveLauC commented 1 year ago

So we are going to implement this feature using the following approach:

Supported Platforms


Any reason why not to call uname(2) on those UNIX (including Linux) platforms? The implementation would be something like this:

I know whoami does not rely on external crate like libc or nix, it's fine, we can link to libc ourselves.

use nix::sys::utsname::uname;

fn main() {
    let res = uname().unwrap();
    println!("{:?}", res.machine());
}
SteveLauC commented 1 year ago

One concern about uname(2) is that I didn't find the full list of architecture strings that could be returned from it. I looked at these two answers this morning:

  1. The architecture strings themselves are in include/generated/compile.h
  2. compile.h is generated from scripts/mkcompile_h

Then I take a look at the contents of mkcompile_h, finding that that arch string is the first command line argument passed to this script:

UTS_MACHINE=$1

Then I was lost because I have no idea how the kernel is built (i.e., how those build scripts are executed, in which order).

Perhaps I should take a look at the POSIX standard to find out if they have any specifications on this returned arch string.

AldaronLau commented 1 year ago

Any reason why not to call uname(2) on those UNIX (including Linux) platforms? The implementation would be something like this:

That's a better solution than the one I suggested, uname() is the way to go.

I know whoami does not rely on external crate like libc or nix, it's fine, we can link to libc ourselves.

use nix::sys::utsname::uname;

fn main() {
    let res = uname().unwrap();
    println!("{:?}", res.machine());
}

Yeah, it will have to include the extern "C" definition manually.

Perhaps I should take a look at the POSIX standard to find out if they have any specifications on this returned arch string.

That sounds like a good plan.