blob: 0ee9b666a4c7493c9d319fdf2c91c053990370da [file] [log] [blame]
Jaewan Kim0bb7cd72024-02-17 00:00:38 +09001// 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
18use anyhow::{anyhow, Result};
19use libfdt::Fdt;
20use std::io::Write;
21use std::path::Path;
22use std::process::{Command, Stdio};
23
24/// Device tree source (dts)
25#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
26pub struct Dts {
27 dts: String,
28}
29
30impl Dts {
31 /// Creates a device tree source from /proc/device-tree style directory
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
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
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}