bpf_loader_lib/meta/
arg_parser.rs1use anyhow::{anyhow, bail, Context, Result};
8use clap::ArgMatches;
9use serde_json::{json, Value};
10
11use super::EunomiaObjectMeta;
12
13pub enum UnpresentVariableAction {
15 FillWithZero,
17 ReportError,
19}
20
21impl EunomiaObjectMeta {
22 pub fn parse_arguments_and_fill_skeleton_variables(
32 &mut self,
33 args: &ArgMatches,
34 on_unpresent: UnpresentVariableAction,
35 ) -> Result<()> {
36 for section in self.bpf_skel.data_sections.iter_mut() {
37 for variable in section.variables.iter_mut() {
38 if variable.name.starts_with("__eunomia_dummy") {
39 continue;
40 }
41 if variable.ty == "bool" {
42 let flag = args.get_one::<bool>(&variable.name).unwrap();
43 variable.value = Some(json!(flag));
44 } else {
45 let user_value = args
46 .get_one::<String>(&variable.name)
47 .map(|v| v.to_string());
48 let parsed_value = if let Some(user_value) = user_value {
49 Some(parse_value(&variable.ty, user_value).with_context(|| {
50 anyhow!("Failed to parse user input value of `{}`", variable.name)
51 })?)
52 } else {
53 match on_unpresent {
54 UnpresentVariableAction::FillWithZero => {
55 None
57 }
58 UnpresentVariableAction::ReportError => bail!(
59 "Variable `{}` has neither default values nor command-line sources",
60 variable.name
61 ),
62 }
63 };
64 variable.value = parsed_value;
65 }
66 }
67 }
68 self.debug_verbose = args.get_flag("verbose");
69 Ok(())
70 }
71}
72
73macro_rules! parse_value_decl {
74 ($raw_value: expr, $input_ty_name: expr, $(($type_name: expr, $to_type: ty)), * ) => {
75 {
76 use anyhow::{anyhow, Context};
77 use serde_json::json;
78 match $input_ty_name {
79 $(
80 $type_name => Some(json!(
81 $raw_value.parse::<$to_type>().with_context(|| anyhow!("Failed to parse `{}` into {}", $raw_value, stringify!($to_type)))?
82 )),
83 )*
84 _ => None
85 }
86 }
87 };
88}
89
90fn parse_value(ty: &str, v: impl AsRef<str>) -> Result<Value> {
91 let s = v.as_ref();
92 let result = parse_value_decl!(
93 s,
94 ty,
95 ("bool", bool),
96 ("pid_t", i32),
97 ("int", i32),
98 ("short", i16),
99 ("long", i64),
100 ("long long", i64),
101 ("unsigned int", u32),
102 ("unsigned short", u16),
103 ("unsigned long long", u64),
104 ("float", f32),
105 ("double", f64)
106 );
107 if let Some(v) = result {
108 Ok(v)
109 } else if ty.starts_with("char[") {
110 Ok(json!(s))
111 } else {
112 bail!("Not supporting parsing into type `{}`", ty);
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use serde_json::json;
119
120 use crate::{
121 meta::{arg_parser::UnpresentVariableAction, EunomiaObjectMeta},
122 tests::get_assets_dir,
123 };
124
125 #[test]
126 fn test_arg_parser() {
127 let mut skel = serde_json::from_str::<EunomiaObjectMeta>(
128 &std::fs::read_to_string(get_assets_dir().join("arg_builder_test").join("skel.json"))
129 .unwrap(),
130 )
131 .unwrap();
132 let cmd = skel.build_argument_parser().unwrap();
133 let matches = cmd
134 .try_get_matches_from([
135 "myprog",
136 "-1",
137 "1234",
138 "--const_val_2",
139 "2345",
140 "--const_val_3",
141 "abcdefg",
142 "--boolflag",
143 "--bss_val_1",
144 "7890",
145 ])
146 .unwrap();
147 skel.parse_arguments_and_fill_skeleton_variables(
148 &matches,
149 UnpresentVariableAction::FillWithZero,
150 )
151 .unwrap();
152 println!("{:#?}", skel.bpf_skel.data_sections);
153 let sections = &skel.bpf_skel.data_sections;
154 assert_eq!(sections[0].variables[0].value, Some(json!(1234)));
155 assert_eq!(sections[0].variables[1].value, Some(json!(2345)));
156 assert_eq!(sections[0].variables[2].value, Some(json!("abcdefg")));
157 assert_eq!(sections[0].variables[3].value, Some(json!(true)));
158 assert_eq!(sections[1].variables[0].value, Some(json!(7890)));
159 }
160 #[test]
161 #[should_panic = "Failed to parse `abcdefg` into i32"]
162 fn test_arg_parser_with_invalid_value_1() {
163 let mut skel = serde_json::from_str::<EunomiaObjectMeta>(
164 &std::fs::read_to_string(get_assets_dir().join("arg_builder_test").join("skel.json"))
165 .unwrap(),
166 )
167 .unwrap();
168 let cmd = skel.build_argument_parser().unwrap();
169 let matches = cmd
170 .try_get_matches_from(["myprog", "-1", "abcdefg"])
171 .unwrap();
172 skel.parse_arguments_and_fill_skeleton_variables(
173 &matches,
174 UnpresentVariableAction::FillWithZero,
175 )
176 .unwrap();
177 }
178 #[test]
179 #[should_panic = "Failed to parse `111111111111111111` into i32"]
180 fn test_arg_parser_with_invalid_value_2() {
181 let mut skel = serde_json::from_str::<EunomiaObjectMeta>(
182 &std::fs::read_to_string(get_assets_dir().join("arg_builder_test").join("skel.json"))
183 .unwrap(),
184 )
185 .unwrap();
186 let cmd = skel.build_argument_parser().unwrap();
187 let matches = cmd
188 .try_get_matches_from(["myprog", "-1", "111111111111111111"])
189 .unwrap();
190 skel.parse_arguments_and_fill_skeleton_variables(
191 &matches,
192 UnpresentVariableAction::FillWithZero,
193 )
194 .unwrap();
195 }
196 #[test]
197 fn test_arg_parser_with_true_boolflag() {
198 let mut skel = serde_json::from_str::<EunomiaObjectMeta>(
199 &std::fs::read_to_string(get_assets_dir().join("arg_builder_test").join("skel.json"))
200 .unwrap(),
201 )
202 .unwrap();
203 let cmd = skel.build_argument_parser().unwrap();
204 let matches = cmd.try_get_matches_from(["myprog"]).unwrap();
205 skel.parse_arguments_and_fill_skeleton_variables(
206 &matches,
207 UnpresentVariableAction::FillWithZero,
208 )
209 .unwrap();
210 assert_eq!(
211 skel.bpf_skel.data_sections[0].variables[4].value,
212 Some(json!(true))
213 );
214 }
215}