cache/
main.rs

1use std::time::Instant;
2
3use clap::Parser;
4use miette::IntoDiagnostic;
5use naming::{GetFlags, dynamic_naming_factory};
6use secgate::TwzError;
7use tracing::Level;
8use twizzler::object::{MapFlags, ObjID};
9
10#[secgate::gatecall]
11pub fn hold(id: ObjID, flags: MapFlags) -> Result<bool, TwzError> {}
12#[secgate::gatecall]
13pub fn drop(id: ObjID, flags: MapFlags) -> Result<bool, TwzError> {}
14#[secgate::gatecall]
15pub fn preload(id: ObjID) -> Result<(), TwzError> {}
16#[secgate::gatecall]
17pub fn stat(_id: ObjID) -> Result<(), TwzError> {}
18#[secgate::gatecall]
19pub fn list_nth(nth: u64) -> Result<Option<CachedStats>, TwzError> {}
20
21#[derive(Debug, Clone, Copy)]
22#[repr(C)]
23pub struct CachedStats {
24    pub id: ObjID,
25    pub start: Instant,
26    pub flags: MapFlags,
27    pub addr: u64,
28}
29
30#[derive(clap::Args, Clone, Debug)]
31struct TrailingArgs {
32    #[arg(
33        help("List of names or object IDs"),
34        trailing_var_arg = true,
35        allow_hyphen_values = true
36    )]
37    args: Vec<String>,
38}
39
40#[derive(clap::Subcommand, Clone, Debug)]
41enum Command {
42    #[clap(about = "Hold an object.")]
43    Hold(TrailingArgs),
44    #[clap(about = "Drop holds on an object.")]
45    Drop(TrailingArgs),
46    #[clap(about = "Preload an object.")]
47    Preload(TrailingArgs),
48    #[clap(about = "Print stats about an object.")]
49    Stat(TrailingArgs),
50    #[clap(about = "List held objects.")]
51    List,
52}
53
54#[derive(clap::Parser, Clone)]
55struct Args {
56    #[clap(subcommand)]
57    cmd: Command,
58}
59
60fn do_hold(id: ObjID) -> twizzler::Result<()> {
61    tracing::info!("do hold: {}", id);
62    hold(id, MapFlags::READ)?;
63    hold(id, MapFlags::READ | MapFlags::EXEC)?;
64    hold(id, MapFlags::READ | MapFlags::NO_NULLPAGE)?;
65    hold(id, MapFlags::READ | MapFlags::WRITE)?;
66    hold(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
67    Ok(())
68}
69
70fn do_drop(id: ObjID) -> twizzler::Result<()> {
71    tracing::info!("do drop: {}", id);
72    drop(id, MapFlags::READ)?;
73    drop(id, MapFlags::READ | MapFlags::EXEC)?;
74    drop(id, MapFlags::READ | MapFlags::NO_NULLPAGE)?;
75    drop(id, MapFlags::READ | MapFlags::WRITE)?;
76    drop(id, MapFlags::READ | MapFlags::WRITE | MapFlags::PERSIST)?;
77    Ok(())
78}
79
80fn do_preload(id: ObjID) -> twizzler::Result<()> {
81    tracing::info!("do preload: {}", id);
82    preload(id)
83}
84
85fn do_stat(id: ObjID) -> twizzler::Result<()> {
86    tracing::info!("do stat: {}", id);
87    stat(id)
88}
89
90fn per_arg(arg: &str, cb: fn(ObjID) -> twizzler::Result<()>) -> twizzler::Result<()> {
91    if let Ok(id) = u128::from_str_radix(arg, 16) {
92        match cb(id.into()) {
93            Ok(_) => return twizzler::Result::Ok(()),
94            Err(e) => tracing::debug!(
95                "failed to operate on parsed object ID {} ({}), trying again with name",
96                e,
97                id
98            ),
99        }
100    }
101    match dynamic_naming_factory()
102        .unwrap()
103        .get(arg, GetFlags::FOLLOW_SYMLINK)
104    {
105        Err(e) => {
106            tracing::warn!("could not resolve {}: {}", arg, e);
107        }
108        Ok(ns) => match ns.kind {
109            naming::NsNodeKind::Namespace => {
110                tracing::debug!("enumerating directory {}", arg);
111                match dynamic_naming_factory()
112                    .unwrap()
113                    .enumerate_names_nsid(ns.id, 0, usize::MAX)
114                {
115                    Ok(nodes) => {
116                        for node in nodes {
117                            if let Ok(name) = node.name() {
118                                if name != "." && name != ".." {
119                                    let name = format!("{}/{}", arg, name);
120                                    let _ = per_arg(name.as_str(), cb);
121                                }
122                                // TODO: track error for ret val
123                            }
124                        }
125                    }
126                    Err(e) => {
127                        tracing::warn!("could not enumerate directory {}: {}", arg, e);
128                    }
129                }
130            }
131            naming::NsNodeKind::Object => {
132                if let Err(e) = cb(ns.id) {
133                    tracing::warn!("could not operate on {}: {}", arg, e);
134                }
135            }
136            naming::NsNodeKind::SymLink => {
137                tracing::warn!("cannot hold / preload symlinks")
138            }
139        },
140    }
141    Ok(())
142}
143
144fn main() -> miette::Result<()> {
145    tracing::subscriber::set_global_default(
146        tracing_subscriber::fmt()
147            .with_max_level(Level::DEBUG)
148            .without_time()
149            .finish(),
150    )
151    .unwrap();
152
153    let args = Args::try_parse().into_diagnostic()?;
154
155    let mut errs = false;
156    match args.cmd {
157        Command::Hold(args) => {
158            for arg in args.args {
159                if per_arg(&arg, do_hold).is_err() {
160                    errs = true;
161                }
162            }
163        }
164        Command::Drop(args) => {
165            for arg in args.args {
166                if per_arg(&arg, do_drop).is_err() {
167                    errs = true;
168                }
169            }
170        }
171        Command::Preload(args) => {
172            for arg in args.args {
173                if per_arg(&arg, do_preload).is_err() {
174                    errs = true;
175                }
176            }
177        }
178        Command::Stat(args) => {
179            for arg in args.args {
180                if per_arg(&arg, do_stat).is_err() {
181                    errs = true;
182                }
183            }
184        }
185        Command::List => {
186            let mut i = 0;
187            while let Some(info) = list_nth(i).into_diagnostic()? {
188                println!(
189                    "{} {:?} {:x} {} seconds old",
190                    info.id,
191                    info.flags,
192                    info.addr,
193                    (Instant::now() - info.start).as_secs_f32()
194                );
195                i += 1;
196            }
197        }
198    }
199
200    if errs {
201        miette::bail!("errors occurred")
202    }
203    Ok(())
204}