driver_tools/subcommands/list_devices/
mod.rs

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