patchelf/
lib.rs

1//! Rust FFI for patchelf
2//! ## Example for print soname.
3//! ```ignore
4//! PatchElf::config()
5//!     .input("libpng.so")
6//!     .print_soname()
7//!     .patch();
8//! ```
9//! ## Example for set soname.
10//! ```ignore
11//! PatchElf::config()
12//!     .input("libpng.so")
13//!     .output("libpng2.so")
14//!     .set_soname("libpng2.so")
15//!     .patch();
16//! ```
17
18use std::ffi::CString;
19pub struct PatchElf {
20    debug: bool,
21    inputs: Vec<String>,
22    output: Option<String>,
23    action: PatchAction,
24    page_size: Option<isize>,
25    allowed_rpath_prefixes: Vec<String>,
26}
27
28pub enum PatchAction {
29    Nop,
30    SetSoname { so_name: String },
31    PrintSoName,
32    SetOsAbi { abi: String },
33    SetInterpreter { interpreter: String },
34    ShrinkRpath,
35    SetRpath { rpath: String },
36    RemoveRpath,
37    AddRpath { rpath: String },
38    ForceRpath,
39    AddNeeded { needed: String },
40    RemoveNeeded { needed: String },
41    ReplaceNeeded { from: String, to: String },
42}
43
44extern "C" {
45    fn patchelf_run() -> bool;
46    fn patchelf_clear();
47    fn patchelf_debug();
48    fn patchelf_set_input(name: *const i8);
49    fn patchelf_set_soname(name: *const i8);
50    fn patchelf_print_soname();
51    fn patchelf_set_output(name: *const i8);
52    fn patchelf_set_page_size(size: isize);
53    fn patchelf_set_osabi(name: *const i8);
54    fn patchelf_set_interpreter(name: *const i8);
55    fn patchelf_shrink_rpath();
56    fn patchelf_set_rpath(name: *const i8);
57    fn patchelf_remove_rpath();
58    fn patchelf_add_rpath(name: *const i8);
59    fn patchelf_force_rpath();
60    fn patchelf_allowed_rpath_prefixes(name: *const i8);
61    fn patchelf_add_needed(name: *const i8);
62    fn patchelf_remove_needed(name: *const i8);
63    fn patchelf_replace_needed(from: *const i8, to: *const i8);
64}
65impl PatchElf {
66    pub fn config() -> Self {
67        Self {
68            debug: false,
69            inputs: vec![],
70            output: None,
71            action: PatchAction::Nop,
72            page_size: None,
73            allowed_rpath_prefixes: vec![],
74        }
75    }
76
77    pub fn debug(mut self) -> Self {
78        self.debug = true;
79        self
80    }
81
82    pub fn page_size(mut self, page_size: isize) -> Self {
83        self.page_size = Some(page_size);
84        self
85    }
86
87    pub fn input(mut self, name: &str) -> Self {
88        self.inputs.push(name.to_string());
89        self
90    }
91
92    pub fn output(mut self, name: &str) -> Self {
93        self.output = Some(name.to_string());
94        self
95    }
96
97    pub fn set_soname(mut self, name: &str) -> Self {
98        self.action = PatchAction::SetSoname {
99            so_name: name.to_string(),
100        };
101        self
102    }
103
104    pub fn print_soname(mut self) -> Self {
105        self.action = PatchAction::PrintSoName;
106        self
107    }
108
109    pub fn set_osabi(mut self, name: &str) -> Self {
110        self.action = PatchAction::SetOsAbi { 
111            abi: name.to_string(),
112        };
113        self
114    }
115
116    pub fn set_interpreter(mut self, name: &str) -> Self {
117        self.action = PatchAction::SetInterpreter {
118            interpreter: name.to_string(),
119        };
120        self
121    }
122
123    pub fn shrink_rpath(mut self) -> Self {
124        self.action = PatchAction::ShrinkRpath;
125        self
126    }
127
128    pub fn remove_rpath(mut self) -> Self {
129        self.action = PatchAction::RemoveRpath;
130        self
131    }
132
133    pub fn force_rpath(mut self) -> Self {
134        self.action = PatchAction::ForceRpath;
135        self
136    }
137
138    pub fn set_set_rpath(mut self, name: &str) -> Self {
139        self.action = PatchAction::SetRpath {
140            rpath: name.to_string(),
141        };
142        self
143    }
144
145    pub fn set_add_rpath(mut self, name: &str) -> Self {
146        self.action = PatchAction::AddRpath {
147            rpath: name.to_string(),
148        };
149        self
150    }
151
152    pub fn allowed_rpath_prefixes(mut self, name: &str) -> Self {
153        self.allowed_rpath_prefixes.push(name.to_string());
154        self
155    }
156
157    pub fn set_add_needed(mut self, name: &str) -> Self {
158        self.action = PatchAction::AddNeeded {
159            needed: name.to_string(),
160        };
161        self
162    }
163
164    pub fn set_remove_needed(mut self, name: &str) -> Self {
165        self.action = PatchAction::RemoveNeeded {
166            needed: name.to_string(),
167        };
168        self
169    }
170
171    pub fn set_replace_needed(mut self, from: &str, to: &str) -> Self {
172        self.action = PatchAction::ReplaceNeeded {
173            from: from.to_string(),
174            to: to.to_string()
175        };
176        self
177    }
178
179    pub fn patch(&self) -> bool {
180        unsafe {
181            patchelf_clear();
182            if self.debug {
183                patchelf_debug();
184            }
185            for input in &self.inputs {
186                let c_name = CString::new(input.as_str()).unwrap();
187                patchelf_set_input(c_name.as_ptr());
188            }
189            if let Some(output) = &self.output {
190                let c_name = CString::new(output.as_str()).unwrap();
191                patchelf_set_output(c_name.as_ptr());
192            }
193            if let Some(page_size) = &self.page_size {
194                patchelf_set_page_size(*page_size);
195            }
196            for prefix in &self.allowed_rpath_prefixes {
197                let c_name = CString::new(prefix.as_str()).unwrap();
198                patchelf_allowed_rpath_prefixes(c_name.as_ptr());
199            }
200            match &self.action {
201                PatchAction::PrintSoName => {
202                    patchelf_print_soname();
203                }
204                PatchAction::SetSoname { so_name } => {
205                    let c_name = CString::new(so_name.as_str()).unwrap();
206                    patchelf_set_soname(c_name.as_ptr());
207                }
208                PatchAction::SetOsAbi { abi } => {
209                    let c_name = CString::new(abi.as_str()).unwrap();
210                    patchelf_set_osabi(c_name.as_ptr()); 
211                }
212                PatchAction::SetInterpreter { interpreter } => {
213                    let c_name = CString::new(interpreter.as_str()).unwrap();
214                    patchelf_set_interpreter(c_name.as_ptr()); 
215                }
216                PatchAction::ShrinkRpath => {
217                    patchelf_shrink_rpath();
218                }
219                PatchAction::SetRpath { rpath } => {
220                    let c_name = CString::new(rpath.as_str()).unwrap();
221                    patchelf_set_rpath(c_name.as_ptr());  
222                }
223                PatchAction::RemoveRpath => {
224                    patchelf_remove_rpath();
225                }
226                PatchAction::ForceRpath => {
227                    patchelf_force_rpath();
228                }
229                PatchAction::AddRpath { rpath } => {
230                    let c_name = CString::new(rpath.as_str()).unwrap();
231                    patchelf_add_rpath(c_name.as_ptr());  
232                }
233                PatchAction::AddNeeded { needed } => {
234                    let c_name = CString::new(needed.as_str()).unwrap();
235                    patchelf_add_needed(c_name.as_ptr());  
236                }
237                PatchAction::RemoveNeeded { needed } => {
238                    let c_name = CString::new(needed.as_str()).unwrap();
239                    patchelf_remove_needed(c_name.as_ptr());  
240                }
241                PatchAction::ReplaceNeeded { from, to } => {
242                    let from = CString::new(from.as_str()).unwrap();
243                    let to = CString::new(to.as_str()).unwrap();
244                    patchelf_replace_needed(from.as_ptr(), to.as_ptr());  
245                }
246                _ => {}
247            }
248            return patchelf_run();
249        }
250    }
251}