-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.rs
More file actions
147 lines (120 loc) · 3.75 KB
/
Copy pathmain.rs
File metadata and controls
147 lines (120 loc) · 3.75 KB
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
146
147
use std::env;
use std::path::PathBuf;
use std::process::exit;
use chromalog::{error, info, warn, ChromaLog, ColorConfig, LevelFilter};
use clap::Parser;
use elf::ElfBytes;
use elf::endian::AnyEndian;
use glob::PatternError;
use subprocess::Exec;
#[derive(Parser, Debug)]
#[command(about, long_about = None, arg_required_else_help = true)]
struct Args {
#[arg(long, env = "APPDIR")]
appdir: Option<PathBuf>,
#[arg(long, env = "GLIBC_VERSION")]
glibc_version: Option<String>,
#[arg(long, default_value_t = false)]
plugin_type: bool,
#[arg(long, default_value_t = false)]
plugin_api_version: bool,
// note: cannot use env here because it does not accept any string as true
// needs to be handled in parse_args()
#[arg(long, default_value_t = false)]
debug: bool,
}
fn parse_args() -> Args {
let mut args = Args::parse();
if args.plugin_type {
println!("input");
// println!("post-processing");
exit(0);
}
if args.plugin_api_version {
println!("0");
exit(0);
}
if env::var_os("DEBUG").is_some() {
args.debug = true;
}
if args.appdir.is_none() {
error!("AppDir not specified");
exit(1);
}
args
}
fn configure_logging(args: &Args) {
let level_filter;
// note: should be done in reverse order as we use an else-if chain
// i.e., from most to least verbose
if args.debug {
level_filter = LevelFilter::Debug;
} else {
level_filter = LevelFilter::Info;
}
// unwrap() may not be the cleanest solution, but if setting up logging _really_ fails, it's
// acceptable for the program to just terminate with an error message
ChromaLog::init(level_filter, ColorConfig::default(), None).unwrap();
}
fn process_file(path: PathBuf, glibc_version: &str) {
let proc = Exec::cmd("polyfill-glibc")
.arg(&path)
.arg(format!("--target-glibc={}", glibc_version))
.join();
match proc {
Err(error) => {
error!("Could not run polyfill-glibc: {}", error);
}
Ok(status) => {
if !status.success() {
warn!("polyfill-glibc process failed");
}
},
}
}
fn process(files: Vec<PathBuf>, glibc_version: &str) {
if files.is_empty() {
warn!("no files found to process");
}
for entry in files {
let path = entry.as_path();
info!("Processing {}", path.display());
let file = std::fs::read(&path).unwrap();
let elf_file = ElfBytes::<AnyEndian>::minimal_parse(file.as_slice());
match elf_file {
Err(error) => {
warn!("Failed to parse {} as an ELF file, skipping", error);
return;
}
Ok(_) => {
process_file(entry, glibc_version);
}
}
}
}
fn glob_files(pattern: &str) -> Result<Vec<PathBuf>, PatternError> {
let files = glob::glob(pattern)?;
Ok(files.filter_map(Result::ok).filter(|x| x.is_file()).collect())
}
fn main() {
let args = parse_args();
configure_logging(&args);
let appdir = args.appdir.unwrap();
if !appdir.exists() {
error!("AppDir {} does not exist", appdir.display());
exit(1);
}
let libs_path = appdir.join("usr/lib/*");
let bins_path = appdir.join("usr/lib/*");
if !args.glibc_version.is_some() {
error!("glibc version not specified");
exit(1);
}
let glibc_version = args.glibc_version.unwrap();
info!("Processing libs");
let libs = glob_files(libs_path.to_str().unwrap()).unwrap();
process(libs, glibc_version.as_str());
info!("Processing bins");
let bins = glob_files(bins_path.to_str().unwrap()).unwrap();
process(bins, glibc_version.as_str());
}