1use crate::{
6 cli::SubCommand,
7 command::{print_table, CommandError, Tabled},
8 device::with_device,
9 job::Job,
10 vtpm::{RefreshAction, VtpmSession},
11};
12use clap::Args;
13
14struct CacheRow {
15 handle: String,
16 class: String,
17 details: String,
18}
19
20impl Tabled for CacheRow {
21 fn headers() -> Vec<String> {
22 vec![
23 "HANDLE".to_string(),
24 "TYPE".to_string(),
25 "DETAILS".to_string(),
26 ]
27 }
28
29 fn row(&self) -> Vec<String> {
30 vec![
31 self.handle.clone(),
32 self.class.clone(),
33 self.details.clone(),
34 ]
35 }
36}
37
38#[derive(Args, Debug)]
40#[command(about = "Lists cached TPM objects.")]
41pub struct Cache {}
42
43impl Cache {
44 fn refresh_cache(job: &mut Job) -> Result<(), CommandError> {
45 with_device(job.device.clone(), |dev| {
46 let vhandles: Vec<u32> = job.cache.contexts.keys().copied().collect();
47 let mut handles_to_remove = Vec::new();
48 let mut encountered_error: Option<CommandError> = None;
49
50 for vhandle in vhandles {
51 if let Some(context) = job.cache.contexts.get_mut(&vhandle) {
52 match context.refresh(dev) {
53 Ok(RefreshAction::Keep) => {}
54 Ok(RefreshAction::Stale) => {
55 log::debug!("vtpm:{vhandle:08x} is stale");
56 handles_to_remove.push(vhandle);
57 }
58 Ok(RefreshAction::Updated(context)) => {
59 if let Some(session) = job
60 .cache
61 .contexts
62 .get_mut(&vhandle)
63 .and_then(|ctx| ctx.as_any_mut().downcast_mut::<VtpmSession>())
64 {
65 session.context = *context;
66 job.cache.mark_dirty(vhandle);
67 } else {
68 log::error!("vtpm:{vhandle:08x}: context type mismatch");
69 handles_to_remove.push(vhandle);
70 }
71 }
72 Err(e) => {
73 log::warn!("vtpm:{vhandle:08x}: {e}");
74 handles_to_remove.push(vhandle);
75 if encountered_error.is_none() {
76 encountered_error = Some(CommandError::from(e));
77 }
78 }
79 }
80 }
81 }
82
83 for vhandle in handles_to_remove {
84 if let Err(e) = job.cache.remove(dev, vhandle) {
85 log::error!("vtpm:{vhandle:08x}: {e}");
86 if encountered_error.is_none() {
87 encountered_error = Some(CommandError::from(e));
88 }
89 }
90 }
91
92 if let Some(err) = encountered_error {
93 Err(err)
94 } else {
95 Ok(())
96 }
97 })
98 }
99}
100
101impl SubCommand for Cache {
102 fn run(&self, job: &mut Job) -> Result<(), CommandError> {
103 Self::refresh_cache(job)?;
104
105 let mut rows: Vec<CacheRow> = job
106 .cache
107 .contexts
108 .values()
109 .map(|ctx| CacheRow {
110 handle: format!("{:08x}", ctx.handle()),
111 class: ctx.class().to_string(),
112 details: ctx.details(),
113 })
114 .collect();
115 rows.sort_unstable_by(|a, b| a.handle.cmp(&b.handle));
116
117 print_table(&mut job.writer, &rows)?;
118 Ok(())
119 }
120}