// Copyright 2024 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //! Device tree source (dts) for comparing device tree contents //! i.e. sorted dts decompiled by `dtc -s -O dts`. use anyhow::{anyhow, Result}; use libfdt::Fdt; use std::io::Write; use std::path::Path; use std::process::{Command, Stdio}; /// Device tree source (dts) #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct Dts { dts: String, } impl Dts { /// Creates a device tree source from /proc/device-tree style directory pub fn from_fs(path: &Path) -> Result { let path = path.to_str().unwrap(); let res = Command::new("./dtc_static") .args(["-f", "-s", "-I", "fs", "-O", "dts", path]) .output()?; if !res.status.success() { return Err(anyhow!("Failed to run dtc_static, res={res:?}")); } Ok(Self { dts: String::from_utf8(res.stdout)? }) } /// Creates a device tree source from dtb pub fn from_dtb(path: &Path) -> Result { let path = path.to_str().unwrap(); let res = Command::new("./dtc_static") .args(["-f", "-s", "-I", "dtb", "-O", "dts", path]) .output()?; if !res.status.success() { return Err(anyhow!("Failed to run dtc_static, res={res:?}")); } Ok(Self { dts: String::from_utf8(res.stdout)? }) } /// Creates a device tree source from Fdt pub fn from_fdt(fdt: &Fdt) -> Result { let mut dtc = Command::new("./dtc_static") .args(["-f", "-s", "-I", "dtb", "-O", "dts"]) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn()?; { let mut stdin = dtc.stdin.take().unwrap(); stdin.write_all(fdt.as_slice())?; // Explicitly drop stdin to avoid indefinite blocking } let res = dtc.wait_with_output()?; if !res.status.success() { return Err(anyhow!("Failed to run dtc_static, res={res:?}")); } Ok(Self { dts: String::from_utf8(res.stdout)? }) } }