1 // Copyright 2024 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! Device tree source (dts) for comparing device tree contents 16 //! i.e. sorted dts decompiled by `dtc -s -O dts`. 17 18 use anyhow::{anyhow, Result}; 19 use libfdt::Fdt; 20 use std::io::Write; 21 use std::path::Path; 22 use std::process::{Command, Stdio}; 23 24 /// Device tree source (dts) 25 #[derive(Debug, Eq, PartialEq, Ord, PartialOrd)] 26 pub struct Dts { 27 dts: String, 28 } 29 30 impl Dts { 31 /// Creates a device tree source from /proc/device-tree style directory from_fs(path: &Path) -> Result<Self>32 pub fn from_fs(path: &Path) -> Result<Self> { 33 let path = path.to_str().unwrap(); 34 let res = Command::new("./dtc_static") 35 .args(["-f", "-s", "-I", "fs", "-O", "dts", path]) 36 .output()?; 37 if !res.status.success() { 38 return Err(anyhow!("Failed to run dtc_static, res={res:?}")); 39 } 40 Ok(Self { dts: String::from_utf8(res.stdout)? }) 41 } 42 43 /// Creates a device tree source from dtb from_dtb(path: &Path) -> Result<Self>44 pub fn from_dtb(path: &Path) -> Result<Self> { 45 let path = path.to_str().unwrap(); 46 let res = Command::new("./dtc_static") 47 .args(["-f", "-s", "-I", "dtb", "-O", "dts", path]) 48 .output()?; 49 if !res.status.success() { 50 return Err(anyhow!("Failed to run dtc_static, res={res:?}")); 51 } 52 Ok(Self { dts: String::from_utf8(res.stdout)? }) 53 } 54 55 /// Creates a device tree source from Fdt from_fdt(fdt: &Fdt) -> Result<Self>56 pub fn from_fdt(fdt: &Fdt) -> Result<Self> { 57 let mut dtc = Command::new("./dtc_static") 58 .args(["-f", "-s", "-I", "dtb", "-O", "dts"]) 59 .stdin(Stdio::piped()) 60 .stdout(Stdio::piped()) 61 .spawn()?; 62 63 { 64 let mut stdin = dtc.stdin.take().unwrap(); 65 stdin.write_all(fdt.as_slice())?; 66 // Explicitly drop stdin to avoid indefinite blocking 67 } 68 69 let res = dtc.wait_with_output()?; 70 if !res.status.success() { 71 return Err(anyhow!("Failed to run dtc_static, res={res:?}")); 72 } 73 Ok(Self { dts: String::from_utf8(res.stdout)? }) 74 } 75 } 76