driver_tools/subcommands/list_devices/
mod.rs1pub mod args;
6
7use crate::common::{node_property_key_to_string, node_property_value_to_string};
8use anyhow::{Result, anyhow};
9use args::ListDevicesCommand;
10use fidl_fuchsia_component_decl as fdecl;
11use flex_fuchsia_driver_development as fdd;
12use flex_fuchsia_driver_framework as fdf;
13use fuchsia_driver_dev::Device;
14#[cfg(feature = "fdomain")]
15use fuchsia_driver_dev_fdomain as fuchsia_driver_dev;
16use itertools::Itertools;
17
18trait DevicePrinter {
19 fn print(&self) -> Result<()>;
20 fn print_verbose(&self) -> Result<()>;
21}
22
23impl DevicePrinter for Device {
24 fn print(&self) -> Result<()> {
25 println!("{}", self.get_moniker()?);
26 Ok(())
27 }
28
29 fn print_verbose(&self) -> Result<()> {
30 let moniker = self.get_moniker().expect("Node does not have a moniker");
31 let (_, name) = moniker.rsplit_once('.').unwrap_or(("", &moniker));
32 let topological_path = self.0.topological_path.as_deref().unwrap_or("None");
33 println!("{0: <9}: {1}", "Name", name);
34 println!("{0: <9}: {1}", "Moniker", moniker);
35 println!("{0: <9}: {1}", "Topology", topological_path);
36
37 if self.0.quarantined == Some(true)
38 && self.0.bound_driver_url != Some("unbound".to_string())
39 {
40 println!(
41 "{0: <9}: {1} (quarantined)",
42 "Driver",
43 self.0.bound_driver_url.as_deref().unwrap_or("None")
44 );
45 } else {
46 println!(
47 "{0: <9}: {1}",
48 "Driver",
49 self.0.bound_driver_url.as_deref().unwrap_or("None")
50 );
51 }
52
53 if let Some(ref bus_topology) = self.0.bus_topology {
54 if !bus_topology.is_empty() {
55 println!("\n{0: <9} {1: <9} {2}", "Bus Type", "Stability", "Address",);
56 }
57 for segment in bus_topology {
58 let address = match &segment.address {
59 Some(fdf::DeviceAddress::IntValue(val)) => format!("{val:02X}"),
60 Some(fdf::DeviceAddress::ArrayIntValue(val)) => {
61 val.iter().map(|v| format!("{v:02X}")).join(":")
62 }
63 Some(fdf::DeviceAddress::CharIntValue(val)) => val.to_string(),
64 Some(fdf::DeviceAddress::ArrayCharIntValue(val)) => {
65 val.iter().map(|v| v.to_string()).join(":")
66 }
67 Some(fdf::DeviceAddress::StringValue(val)) => val.to_string(),
68 None => "None".to_string(),
69 _ => "Unknown".to_string(),
70 };
71 println!(
72 "{0: <9} {1: <9} {2}",
73 segment
74 .bus
75 .map(|s| format!("{s:?}").to_uppercase())
76 .unwrap_or_else(|| "Unknown".to_string()),
77 segment
78 .address_stability
79 .map(|s| format!("{s:?}"))
80 .unwrap_or_else(|| "Unknown".to_string()),
81 address,
82 );
83 }
84 if !bus_topology.is_empty() {
85 println!("");
86 }
87 }
88
89 if let Some(ref node_property_list) = self.0.node_property_list {
90 println!("{} Properties", node_property_list.len());
91 for i in 0..node_property_list.len() {
92 let node_property = &node_property_list[i];
93 println!(
94 "[{:>2}/ {:>2}] : Key {:30} Value {}",
95 i + 1,
96 node_property_list.len(),
97 node_property_key_to_string(&node_property.key),
98 node_property_value_to_string(&node_property.value),
99 );
100 }
101 } else {
102 println!("0 Properties");
103 }
104
105 if let Some(ref offer_list) = self.0.offer_list {
106 println!("{} Offers", offer_list.len());
107 for i in 0..offer_list.len() {
108 if let fdecl::Offer::Service(service) = &offer_list[i] {
109 println!("Service: {}", service.target_name.as_deref().unwrap_or("<unknown>"));
110 if let Some(fdecl::Ref::Child(source)) = service.source.as_ref() {
111 println!(" Source: {}", source.name);
112 }
113 if let Some(filter) = &service.source_instance_filter {
114 println!(" Instances: {}", filter.join(" "));
115 }
116 }
117 }
118 } else {
119 println!("0 Offers");
120 }
121 println!("");
122 Ok(())
123 }
124}
125
126pub async fn list_devices(
127 cmd: ListDevicesCommand,
128 driver_development_proxy: fdd::ManagerProxy,
129) -> Result<()> {
130 let devices: Vec<Device> = match cmd.device {
131 Some(device) => {
132 fuchsia_driver_dev::get_device_info(&driver_development_proxy, &[device], cmd.exact)
133 .await?
134 }
135 None => {
136 fuchsia_driver_dev::get_device_info(&driver_development_proxy, &[], cmd.exact).await?
137 }
138 }
139 .into_iter()
140 .filter(|d| !cmd.unbound || d.bound_driver_url == Some("unbound".to_string()))
141 .map(|device_info| Device::from(device_info))
142 .collect();
143
144 if !devices.is_empty() {
145 if cmd.verbose {
146 for device in devices {
147 device.print_verbose()?;
148 }
149 } else {
150 for device in devices {
151 device.print()?;
152 }
153 }
154 } else {
155 if cmd.fail_on_missing {
156 return Err(anyhow!("No devices found."));
157 } else {
158 println!("No devices found.");
159 }
160 }
161
162 Ok(())
163}