mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
pvimg: info: Provide two JSON output variants: pretty and minify
Add two JSON output variants: pretty and minify. The desired variant can be selected via '--format json:pretty' and '--format json:minify'. Using '--format json' without a variant defaults to pretty. Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Marc Hartmayer <marc@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
48c8fc8321
commit
012025595f
+135
-14
@@ -2,9 +2,15 @@
|
||||
//
|
||||
// Copyright IBM Corp. 2024
|
||||
|
||||
use std::{env, fmt::Display, path::PathBuf};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use std::string::ToString;
|
||||
use std::{env, ffi::OsStr, path::PathBuf};
|
||||
|
||||
use clap::{ArgGroup, Args, Command, CommandFactory, Parser, ValueEnum, ValueHint};
|
||||
use clap::{
|
||||
builder::PossibleValue, Arg, ArgGroup, Args, Command, CommandFactory, Parser, ValueEnum,
|
||||
ValueHint,
|
||||
};
|
||||
use log::warn;
|
||||
use utils::{CertificateOptions, DeprecatedVerbosityOptions};
|
||||
|
||||
@@ -206,21 +212,112 @@ pub struct CreateBootImageLegacyFlags {
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
|
||||
pub enum OutputFormat {
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug)]
|
||||
pub enum OutputFormatKind {
|
||||
/// JSON format.
|
||||
Json,
|
||||
}
|
||||
|
||||
impl Display for OutputFormat {
|
||||
impl Display for OutputFormatKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Self::Json => "JSON",
|
||||
match self {
|
||||
Self::Json => write!(f, "JSON"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for OutputFormatKind {
|
||||
type Err = String;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"json" => Ok(Self::Json),
|
||||
_ => Err(format!("Invalid output format: {s}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum OutputFormatVariant {
|
||||
/// Default
|
||||
Default,
|
||||
/// Minified
|
||||
Minify,
|
||||
/// Pretty
|
||||
Pretty,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct OutputFormatSpec {
|
||||
pub kind: OutputFormatKind,
|
||||
pub variant: OutputFormatVariant,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
struct OutputFormatSpecParser;
|
||||
|
||||
impl clap::builder::TypedValueParser for OutputFormatSpecParser {
|
||||
type Value = OutputFormatSpec;
|
||||
|
||||
fn parse_ref(
|
||||
&self,
|
||||
cmd: &Command,
|
||||
arg: Option<&Arg>,
|
||||
value: &OsStr,
|
||||
) -> Result<Self::Value, clap::error::Error> {
|
||||
let s = value.to_string_lossy();
|
||||
let mut parts = s.splitn(2, ':');
|
||||
let arg_name = arg.unwrap().get_id().to_string();
|
||||
let kind_s = parts.next().unwrap().to_ascii_lowercase();
|
||||
let variant_s = parts.next().map(|x| x.to_ascii_lowercase());
|
||||
let kind = kind_s.as_str().parse().map_err(|_| {
|
||||
let mut err =
|
||||
clap::error::Error::new(clap::error::ErrorKind::ValueValidation).with_cmd(cmd);
|
||||
err.insert(
|
||||
clap::error::ContextKind::InvalidArg,
|
||||
clap::error::ContextValue::String(arg_name.clone()),
|
||||
);
|
||||
err.insert(
|
||||
clap::error::ContextKind::InvalidValue,
|
||||
clap::error::ContextValue::String(kind_s.to_string()),
|
||||
);
|
||||
err
|
||||
})?;
|
||||
|
||||
let variant = match (kind, variant_s.as_deref()) {
|
||||
(_, None) => OutputFormatVariant::Default,
|
||||
(_, Some("default")) => OutputFormatVariant::Default,
|
||||
|
||||
(OutputFormatKind::Json, Some("pretty")) => OutputFormatVariant::Pretty,
|
||||
(OutputFormatKind::Json, Some("minify")) => OutputFormatVariant::Minify,
|
||||
(OutputFormatKind::Json, Some(other)) => {
|
||||
let mut err =
|
||||
clap::error::Error::new(clap::error::ErrorKind::ValueValidation).with_cmd(cmd);
|
||||
err.insert(
|
||||
clap::error::ContextKind::InvalidArg,
|
||||
clap::error::ContextValue::String(arg_name),
|
||||
);
|
||||
err.insert(
|
||||
clap::error::ContextKind::InvalidValue,
|
||||
clap::error::ContextValue::String(format!("{kind_s}:{other}")),
|
||||
);
|
||||
Err(err)?
|
||||
}
|
||||
)
|
||||
};
|
||||
|
||||
Ok(OutputFormatSpec { kind, variant })
|
||||
}
|
||||
|
||||
// This is used for shell completion suggestions for `--format`
|
||||
fn possible_values(&self) -> Option<Box<dyn Iterator<Item = PossibleValue> + '_>> {
|
||||
use clap::builder::PossibleValue as PV;
|
||||
|
||||
let vals: Vec<PV> = vec![
|
||||
PV::new("json").help("Pretty-printed machine-readable JSON"),
|
||||
PV::new("json:pretty").help("Pretty-printed machine-readable JSON"),
|
||||
PV::new("json:minify").help("Minified machine-readable JSON"),
|
||||
];
|
||||
Some(Box::new(vals.into_iter()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,9 +333,9 @@ pub struct InfoArgs {
|
||||
#[clap(flatten)]
|
||||
pub input: SeImgInputArgs,
|
||||
|
||||
/// The output format
|
||||
#[arg(long, value_enum)]
|
||||
pub format: OutputFormat,
|
||||
/// Output format
|
||||
#[arg(long, value_parser=OutputFormatSpecParser::default())]
|
||||
pub format: OutputFormatSpec,
|
||||
|
||||
/// Use the key in FILE to decrypt the Secure Execution header.
|
||||
///
|
||||
@@ -793,6 +890,30 @@ mod test {
|
||||
CliOption::new("image", ["/dev/null"]),
|
||||
],
|
||||
)),
|
||||
flat_map_collect(insert(
|
||||
args.clone(),
|
||||
vec![
|
||||
CliOption::new("hdr-key", ["--key", "/dev/null"]),
|
||||
CliOption::new("format", ["--format=json:default"]),
|
||||
CliOption::new("image", ["/dev/null"]),
|
||||
],
|
||||
)),
|
||||
flat_map_collect(insert(
|
||||
args.clone(),
|
||||
vec![
|
||||
CliOption::new("hdr-key", ["--key", "/dev/null"]),
|
||||
CliOption::new("format", ["--format=json:minify"]),
|
||||
CliOption::new("image", ["/dev/null"]),
|
||||
],
|
||||
)),
|
||||
flat_map_collect(insert(
|
||||
args.clone(),
|
||||
vec![
|
||||
CliOption::new("hdr-key", ["--key", "/dev/null"]),
|
||||
CliOption::new("format", ["--format=json:pretty"]),
|
||||
CliOption::new("image", ["/dev/null"]),
|
||||
],
|
||||
)),
|
||||
// separation between keyword and positional args works
|
||||
flat_map_collect(insert(
|
||||
args.clone(),
|
||||
|
||||
@@ -12,30 +12,49 @@ use pv::{
|
||||
};
|
||||
use pvimg::{
|
||||
error::OwnExitCode,
|
||||
uvdata::{KeyExchangeTrait, SeHdr, UvDataTrait},
|
||||
uvdata::{KeyExchangeTrait, SeH, SeHdr, UvDataTrait},
|
||||
};
|
||||
|
||||
use crate::cli::InfoArgs;
|
||||
use crate::cli::{InfoArgs, OutputFormatKind, OutputFormatSpec, OutputFormatVariant};
|
||||
|
||||
pub fn info(opt: &InfoArgs) -> Result<OwnExitCode> {
|
||||
info!(
|
||||
"Reading Secure Execution header {}",
|
||||
opt.input.path.display()
|
||||
);
|
||||
let mut input = open_file(&opt.input.path)?;
|
||||
let mut img = open_file(&opt.input.path)?;
|
||||
let mut output = std::io::stdout();
|
||||
|
||||
SeHdr::seek_sehdr(&mut input, None)?;
|
||||
let hdr = SeHdr::try_from_io(input)?;
|
||||
if let Some(key_path) = &opt.hdr_key {
|
||||
SeHdr::seek_sehdr(&mut img, None)?;
|
||||
let hdr = SeHdr::try_from_io(&mut img)?;
|
||||
let se_hdr = if let Some(key_path) = &opt.hdr_key {
|
||||
let key =
|
||||
SymKey::try_from_data(hdr.key_type(), read_file(key_path, "Reading key")?.into())?;
|
||||
serde_json::to_writer_pretty(&mut output, &hdr.decrypt(&key)?)?;
|
||||
let decrypted_hdr = hdr.decrypt(&key)?;
|
||||
SeH::Decrypted(decrypted_hdr)
|
||||
} else {
|
||||
warn!("WARNING: The Secure Execution header integrity and authenticity was not verified. Specify '--hdr-key' to authenticate it. Do not trust the data without verification.");
|
||||
serde_json::to_writer_pretty(&mut output, &hdr)?;
|
||||
SeH::Encrypted(hdr)
|
||||
};
|
||||
|
||||
match opt.format {
|
||||
OutputFormatSpec {
|
||||
kind: OutputFormatKind::Json,
|
||||
variant,
|
||||
} => {
|
||||
match variant {
|
||||
OutputFormatVariant::Minify => {
|
||||
serde_json::to_writer(&mut output, &se_hdr)?;
|
||||
}
|
||||
OutputFormatVariant::Default | OutputFormatVariant::Pretty => {
|
||||
serde_json::to_writer_pretty(&mut output, &se_hdr)?
|
||||
}
|
||||
}
|
||||
// Make sure the output ends with a new line
|
||||
writeln!(&mut output)?
|
||||
}
|
||||
}
|
||||
writeln!(output)?;
|
||||
output.flush()?;
|
||||
|
||||
Ok(OwnExitCode::Success)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ pub mod misc {
|
||||
pub mod uvdata {
|
||||
pub use crate::pv_utils::{
|
||||
AeadPlainDataTrait, BuilderTrait, ComponentMetadataV1, ControlFlagTrait, ControlFlagsTrait,
|
||||
FlagData, KeyExchangeTrait, PcfV1, PlaintextControlFlagsV1, ScfV1, SeHdr, SeHdrAadV1,
|
||||
FlagData, KeyExchangeTrait, PcfV1, PlaintextControlFlagsV1, ScfV1, SeH, SeHdr, SeHdrAadV1,
|
||||
SeHdrBinV1, SeHdrBuilder, SeHdrData, SeHdrDataV1, SeHdrPlain, SeHdrVersion, SeHdrVersioned,
|
||||
SecretControlFlagsV1, UvDataPlainTrait, UvDataTrait, UvKeyHashesV1,
|
||||
};
|
||||
|
||||
@@ -19,7 +19,7 @@ pub use misc::{round_up, try_copy_slice_to_array};
|
||||
pub use psw::{ShortPsw, PSW, PSW_MASK_BA, PSW_MASK_EA};
|
||||
pub use se_hdr::{
|
||||
ComponentMetadataV1, ControlFlagTrait, ControlFlagsTrait, FlagData, PcfV1,
|
||||
PlaintextControlFlagsV1, ScfV1, SeHdr, SeHdrAadV1, SeHdrBinV1, SeHdrBuilder, SeHdrData,
|
||||
PlaintextControlFlagsV1, ScfV1, SeH, SeHdr, SeHdrAadV1, SeHdrBinV1, SeHdrBuilder, SeHdrData,
|
||||
SeHdrDataV1, SeHdrPlain, SeHdrVersion, SeHdrVersioned, SecretControlFlagsV1,
|
||||
};
|
||||
pub use secured_comp::{ComponentTrait, SecuredComponent, SecuredComponentBuilder};
|
||||
|
||||
@@ -9,9 +9,9 @@ mod hdr_v1;
|
||||
mod keys;
|
||||
|
||||
pub use brb::{
|
||||
ComponentMetadata, ComponentMetadataV1, SeHdr, SeHdrDataV1, SeHdrPlain, SeHdrVersion,
|
||||
ComponentMetadata, ComponentMetadataV1, SeH, SeHdr, SeHdrBinV1, SeHdrData, SeHdrDataV1,
|
||||
SeHdrPlain, SeHdrVersion, SeHdrVersioned,
|
||||
};
|
||||
pub use brb::{SeHdrBinV1, SeHdrData, SeHdrVersioned};
|
||||
pub use builder::SeHdrBuilder;
|
||||
pub use flags::{
|
||||
ControlFlagTrait, ControlFlagsTrait, FlagData, PcfV1, PlaintextControlFlagsV1, ScfV1,
|
||||
|
||||
@@ -47,6 +47,12 @@ pub enum SeHdrVersion {
|
||||
V1 = 0x100,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Serialize)]
|
||||
pub enum SeH {
|
||||
Decrypted(SeHdrPlain),
|
||||
Encrypted(SeHdr),
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, DekuRead, DekuWrite, Serialize)]
|
||||
#[deku(endian = "endian", ctx = "endian: Endian", ctx_default = "Endian::Big")]
|
||||
|
||||
Reference in New Issue
Block a user