-
Notifications
You must be signed in to change notification settings - Fork 6
/
build.rs
145 lines (121 loc) · 5.01 KB
/
build.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use std::env;
use std::fs::File;
use std::io::{Read, Write};
use std::path::PathBuf;
// This generates the `layers::register_defaults` function. Right now the implementation is rather
// dirty and perhaps can be made better using APIs from `ra_ap_hir` or `ra_ap_vfs`, but that's an
// overkill at the moment. We should fix bugs in this if any.
fn main() -> std::io::Result<()> {
let sources_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
.join("src")
.join("layers");
let walker = walkdir::WalkDir::new(&sources_dir);
let mut reg_defaults = Vec::new();
for entry in walker {
let entry = entry.unwrap();
if entry.file_type().is_file() {
eprintln!("Path: {:#?}", entry.path());
let mut file = File::open(entry.path()).unwrap();
let mut content = String::new();
file.read_to_string(&mut content).unwrap();
let ast = syn::parse_file(&content).map_err(|e| {
std::io::Error::new(
std::io::ErrorKind::Other,
format!("file: {:?}, Error: {:?}", entry.path(), e),
)
})?;
for item in ast.items {
if let syn::Item::Fn(ref i) = item {
// The AST contains a Function with `register_defaults` as identifer.
// Collect it to be written to final `layers::register_defaults`.
if i.sig.ident == "register_defaults" {
let mut register_defaults_fn_path = entry
.path()
.strip_prefix(&sources_dir)
.unwrap()
.to_str()
.unwrap()
.to_string()
.replace(std::path::MAIN_SEPARATOR, "::")
.replace("mod.rs", "")
.replace(".rs", "::");
register_defaults_fn_path.push_str("register_defaults()?;");
reg_defaults.push(register_defaults_fn_path);
}
}
}
}
}
let output_str = format!(
r#"
use std::sync::Once;
static INIT: Once = Once::new();
/// Register Default protocol handlers.
///
/// Each [`Layer`][`crate::layer::Layer`] in `scalpel` will be decoded by a certain field in the
/// lower layer for which this particular layer is a payload. For example, [`ipv4::IPv4`] is a
/// payload for [`ethernet::Ethernet`]. Thus while decoding a particular layer, the next layer to
/// be decoded is determined by a value of certain field in the current layer. In the example
/// above, EtherType in the Ethernet header determines the next layer (EtherType: 0x8000
/// corresponds to [`ipv4::IPv4`]).
///
/// To initialize the dissection framework properly, the application should call this function
/// before trying to dissect packets. If this function is not called, all the data is shown as
/// `unprocessed` data in the [`Packet`][`crate::Packet`]
///
/// ```rust
/// # fn main() {{
///
/// let _ = scalpel::register_defaults();
///
/// let packet_data =
/// hex::decode("000573a007d168a3c4f949f686dd600000000020064020010470e5bfdead49572174e82c48872607f8b0400c0c03000000000000001af9c7001903a088300000000080022000da4700000204058c0103030801010402").unwrap();
///
/// let packet = scalpel::Packet::from_bytes(&packet_data, scalpel::ENCAP_TYPE_ETH);
///
/// eprintln!("Packet: {{:#?}}", packet);
///
/// # }}
///
/// ```
///
/// In this function we just call the `register_defaults` functions for each of the currently
/// supported layers.
///
/// When a new layer is defined outside the crate, that particular layer may use a `register_*`
/// function in it's upper layer to request it's dissection. This glues all the dissectors for the
/// layers together.
pub fn register_defaults() -> Result<(), crate::errors::Error> {{
let mut result: Result<(), crate::errors::Error> = Ok(());
fn inner() -> Result<(), crate::errors::Error> {{
// We need to make sure `packet::register_defaults` is initialized first.
crate::packet::register_defaults()?;
// Now all the layers' `register_defaults`
{layers_reg_defaults}
Ok(())
}}
INIT.call_once(|| {{
result = inner();
if let Err(ref e) = result {{
#[cfg(feature = "logging")]
log::error!("Error during register_defaults: {{:#?}}", e);
eprintln!("Error : {{:#?}}", e);
}}
}});
result
}}"#,
layers_reg_defaults = reg_defaults.join("\n")
);
let output_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let outfile_path = output_path.join("register_defaults.rs");
{
let mut outfile = File::create(&outfile_path).unwrap();
let _ = outfile.write(output_str.as_bytes());
let _ = outfile.flush();
}
let _ = std::process::Command::new("rustfmt")
.arg(&outfile_path)
.output()
.expect("Failed to rustfmt");
Ok(())
}