blob: c152607f33f335894d197828ad57382320b03841 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use anyhow::{Context, Error};
use argh::FromArgs;
use fidl_fuchsia_sysinfo::{InterruptControllerInfo, SysInfoMarker, SysInfoProxy};
use fuchsia_component::client::connect_to_protocol;
use std::fmt::Debug;
use std::io::Write;
use {fuchsia_zircon as zx, futures as _};
#[derive(Debug, Clone, Copy, PartialEq)]
enum SystemInfo {
BoardName,
BoardRevision,
BootLoaderVendor,
InterruptController,
SerialNumber,
}
impl std::str::FromStr for SystemInfo {
type Err = String;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value {
"board_name" => Ok(SystemInfo::BoardName),
"board_revision" => Ok(SystemInfo::BoardRevision),
"bootloader_vendor" => Ok(SystemInfo::BootLoaderVendor),
"interrupt_controller" => Ok(SystemInfo::InterruptController),
"serial_number" => Ok(SystemInfo::SerialNumber),
_ => Err(format!("Invalid key: {:?}. ", value)),
}
}
}
fn unwrap_option<T: ToString>(info: Option<T>) -> String {
info.map(|v| v.to_string()).unwrap_or("None".to_string())
}
fn unwrap_option_debug<T: Debug>(t: Option<T>) -> String {
t.map(|t| format!("{:?}", t)).unwrap_or("None".to_string())
}
fn write_board_name_info<W: Write>(
w: &mut W,
board_name_info: (i32, Option<String>),
) -> Result<(), Error> {
if zx::Status::from_raw(board_name_info.0) != zx::Status::OK {
writeln!(w, "zx_status: {}", zx::Status::from_raw(board_name_info.0))?;
}
writeln!(w, "board_name: {}", unwrap_option(board_name_info.1))?;
Ok(())
}
async fn print_board_name_info(provider: SysInfoProxy) -> Result<(), Error> {
let board_name_info = provider.get_board_name().await?;
let mut w = std::io::stdout();
write_board_name_info(&mut w, board_name_info)
.expect("Function write_board_name_info() failed");
Ok(())
}
fn write_board_revision_info<W: Write>(
w: &mut W,
board_revision_info: (i32, u32),
) -> Result<(), Error> {
if zx::Status::from_raw(board_revision_info.0) != zx::Status::OK {
writeln!(w, "zx_status: {}", zx::Status::from_raw(board_revision_info.0))?;
}
writeln!(w, "board_revision: {}", board_revision_info.1)?;
Ok(())
}
async fn print_board_revision_info(provider: SysInfoProxy) -> Result<(), Error> {
let board_revision_info = provider.get_board_revision().await?;
let mut w = std::io::stdout();
write_board_revision_info(&mut w, board_revision_info)
.expect("Function write_board_revision_info() failed");
Ok(())
}
fn write_bootloader_vendor_info<W: Write>(
w: &mut W,
bootloader_vendor_info: (i32, Option<String>),
) -> Result<(), Error> {
if zx::Status::from_raw(bootloader_vendor_info.0) != zx::Status::OK {
writeln!(w, "zx_status: {}", zx::Status::from_raw(bootloader_vendor_info.0))?;
}
writeln!(w, "bootloader_vendor: {}", unwrap_option(bootloader_vendor_info.1))?;
Ok(())
}
async fn print_bootloader_vendor_info(provider: SysInfoProxy) -> Result<(), Error> {
let bootloader_vendor_info = provider.get_bootloader_vendor().await?;
let mut w = std::io::stdout();
write_bootloader_vendor_info(&mut w, bootloader_vendor_info)
.expect("Function write_bootloader_vendor_info() failed");
Ok(())
}
fn write_interrupt_controller_info<W: Write>(
w: &mut W,
interrupt_controller_info: (i32, Option<Box<InterruptControllerInfo>>),
) -> Result<(), Error> {
if zx::Status::from_raw(interrupt_controller_info.0) != zx::Status::OK {
writeln!(w, "zx_status: {}", zx::Status::from_raw(interrupt_controller_info.0))?;
}
writeln!(
w,
"interrupt_controller: {}",
unwrap_option_debug(interrupt_controller_info.1.map(|t| t.type_))
)?;
Ok(())
}
async fn print_interrupt_controller_info(provider: SysInfoProxy) -> Result<(), Error> {
let interrupt_controller_info = provider.get_interrupt_controller_info().await?;
let mut w = std::io::stdout();
write_interrupt_controller_info(&mut w, interrupt_controller_info)
.expect("Function write_interrupt_controller_info() failed");
Ok(())
}
fn write_serial_number<W: Write>(
w: &mut W,
serial_number: Result<String, i32>,
) -> Result<(), Error> {
match serial_number {
Ok(s) => writeln!(w, "serial_number: {}", s)?,
Err(e) => writeln!(w, "zx_status: {}", zx::Status::from_raw(e))?,
}
Ok(())
}
async fn print_serial_number(provider: SysInfoProxy) -> Result<(), Error> {
let serial_number = provider.get_serial_number().await?;
let mut w = std::io::stdout();
write_serial_number(&mut w, serial_number).expect("Function write_serial_number() failed");
Ok(())
}
/// System Information command.
#[derive(Debug, PartialEq, FromArgs)]
struct BuildInfoCmd {
/// valid keys: <board_name> <board_revision> <bootloader_vendor> <interrupt_controller> <serial_number>
#[argh(positional)]
info: SystemInfo,
}
#[fuchsia::main]
async fn main() -> Result<(), Error> {
let args: BuildInfoCmd = argh::from_env();
let provider = connect_to_protocol::<SysInfoMarker>()
.context("Failed to connect to the board info service")?;
match args.info {
SystemInfo::BoardName => print_board_name_info(provider).await?,
SystemInfo::BoardRevision => print_board_revision_info(provider).await?,
SystemInfo::BootLoaderVendor => print_bootloader_vendor_info(provider).await?,
SystemInfo::InterruptController => print_interrupt_controller_info(provider).await?,
SystemInfo::SerialNumber => print_serial_number(provider).await?,
}
Ok(())
}
// =========== Testing the sys-info output ===================
#[cfg(test)]
mod tests {
use super::*;
use fidl_fuchsia_sysinfo::InterruptControllerType;
#[fuchsia::test]
fn test_format_board_name_info() {
// Tests with the BoardName fields set to data.
let board_name_info = (0, Some("butterfly".to_string()));
let mut v = Vec::new();
write_board_name_info(&mut v, board_name_info)
.expect("Testing write_board_name_info() failed");
let write_str = String::from_utf8(v).expect("Failed to convert to string");
let expect_str = concat!("board_name: butterfly\n");
// Verify expressions match
assert_eq!(write_str, expect_str);
// Tests with the BoardName fields set to None.
let board_name_info_none = (0, None);
let mut v_none = Vec::new();
write_board_name_info(&mut v_none, board_name_info_none)
.expect("Testing write_board_name_info() failed");
let write_str_none = String::from_utf8(v_none).expect("Failed to convert to string");
let expect_str_none = concat!("board_name: None\n");
// Verify expression match
assert_eq!(write_str_none, expect_str_none);
}
#[fuchsia::test]
fn test_format_board_revision_info() {
// Tests with the BoardRevision fields set to data.
let board_revision_info = (0, 100);
let mut v = Vec::new();
write_board_revision_info(&mut v, board_revision_info)
.expect("Testing write_board_revision_info() failed");
let write_str = String::from_utf8(v).expect("Failed to convert to string");
let expect_str = concat!("board_revision: 100\n");
// Verify expressions match
assert_eq!(write_str, expect_str);
}
#[fuchsia::test]
fn test_format_bootloader_vendor_info() {
// Tests with the BootloaderVendor fields set to data.
let bootloader_vendor_info = (0, Some("vendor-101".to_string()));
let mut v = Vec::new();
write_bootloader_vendor_info(&mut v, bootloader_vendor_info)
.expect("Testing write_bootloader_vendor_info() failed");
let write_str = String::from_utf8(v).expect("Failed to convert to string");
let expect_str = concat!("bootloader_vendor: vendor-101\n");
// Verify expressions match
assert_eq!(write_str, expect_str);
// Tests with the BootloaderVendor fields set to None.
let bootloader_vendor_info_none = (0, None);
let mut v_none = Vec::new();
write_bootloader_vendor_info(&mut v_none, bootloader_vendor_info_none)
.expect("Testing write_bootloader_vendor_info() failed");
let write_str_none = String::from_utf8(v_none).expect("Failed to convert to string");
let expect_str_none = concat!("bootloader_vendor: None\n");
// Verify expression match
assert_eq!(write_str_none, expect_str_none);
}
#[fuchsia::test]
fn test_format_interrupt_controller_info() {
// Tests with the InterruptControllerInfo fields set to data.
let interrupt_info = InterruptControllerInfo { type_: InterruptControllerType::Apic };
let interrupt_controller_info = (0, Some(Box::new(interrupt_info)));
let mut v = Vec::new();
write_interrupt_controller_info(&mut v, interrupt_controller_info)
.expect("Testing write_interrupt_controller_info() failed");
let write_str = String::from_utf8(v).expect("Failed to convert to string");
let expect_str = concat!("interrupt_controller: Apic\n");
// Verify expressions match
assert_eq!(write_str, expect_str);
// Tests with the InterruptControllerInfo fields set to None.
let interrupt_controller_info_none = (0, None);
let mut v_none = Vec::new();
write_interrupt_controller_info(&mut v_none, interrupt_controller_info_none)
.expect("Testing write_interrupt_controller_info() failed");
let write_str_none = String::from_utf8(v_none).expect("Failed to convert to string");
let expect_str_none = concat!("interrupt_controller: None\n");
// Verify expression match
assert_eq!(write_str_none, expect_str_none);
}
}