summaryrefslogtreecommitdiff
path: root/rust/src
diff options
context:
space:
mode:
Diffstat (limited to 'rust/src')
-rw-r--r--rust/src/headless.rs62
1 files changed, 56 insertions, 6 deletions
diff --git a/rust/src/headless.rs b/rust/src/headless.rs
index 78c04a96..2cc87056 100644
--- a/rust/src/headless.rs
+++ b/rust/src/headless.rs
@@ -18,6 +18,8 @@ use crate::{
};
use std::io;
use std::path::{Path, PathBuf};
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering::SeqCst;
use thiserror::Error;
use crate::enterprise::release_license;
@@ -32,6 +34,9 @@ use std::time::Duration;
static MAIN_THREAD_HANDLE: Mutex<Option<JoinHandle<()>>> = Mutex::new(None);
+/// Used to prevent shutting down Binary Ninja if there are other [`Session`]'s.
+static SESSION_COUNT: AtomicUsize = AtomicUsize::new(0);
+
#[derive(Error, Debug)]
pub enum InitializationError {
#[error("main thread could not be started: {0}")]
@@ -91,6 +96,14 @@ pub struct InitializationOptions {
pub floating_license_duration: Duration,
/// The bundled plugin directory to use.
pub bundled_plugin_directory: PathBuf,
+ /// Whether to initialize user plugins.
+ ///
+ /// Set this to false if your use might be impacted by a user installed plugin.
+ pub user_plugins: bool,
+ /// Whether to initialize repo plugins.
+ ///
+ /// Set this to false if your use might be impacted by a repo installed plugin.
+ pub repo_plugins: bool,
}
impl InitializationOptions {
@@ -98,6 +111,14 @@ impl InitializationOptions {
Self::default()
}
+ pub fn minimal() -> Self {
+ Self {
+ user_plugins: false,
+ repo_plugins: false,
+ ..Self::default()
+ }
+ }
+
/// A license to override with, you can use this to make sure you initialize with a specific license.
///
/// This takes the form of a JSON array. The string should be formed like:
@@ -112,7 +133,7 @@ impl InitializationOptions {
/// If you need to make sure that you do not check out a license set this to false.
///
/// This is really only useful if you have a headless license but are using an enterprise enabled core.
- pub fn with_checkout_license(mut self, should_checkout: bool) -> Self {
+ pub fn with_license_checkout(mut self, should_checkout: bool) -> Self {
self.checkout_license = should_checkout;
self
}
@@ -130,6 +151,18 @@ impl InitializationOptions {
self.floating_license_duration = duration;
self
}
+
+ /// Set this to false if your use might be impacted by a user installed plugin.
+ pub fn with_user_plugins(mut self, should_initialize: bool) -> Self {
+ self.user_plugins = should_initialize;
+ self
+ }
+
+ /// Set this to false if your use might be impacted by a repo installed plugin.
+ pub fn with_repo_plugins(mut self, should_initialize: bool) -> Self {
+ self.repo_plugins = should_initialize;
+ self
+ }
}
impl Default for InitializationOptions {
@@ -141,6 +174,8 @@ impl Default for InitializationOptions {
floating_license_duration: Duration::from_secs(900),
bundled_plugin_directory: bundled_plugin_directory()
.expect("Failed to get bundled plugin directory"),
+ user_plugins: true,
+ repo_plugins: true,
}
}
}
@@ -188,8 +223,11 @@ pub fn init_with_opts(options: InitializationOptions) -> Result<(), Initializati
set_bundled_plugin_directory(options.bundled_plugin_directory);
unsafe {
- BNInitPlugins(true);
- BNInitRepoPlugins();
+ BNInitPlugins(options.user_plugins);
+ if options.repo_plugins {
+ // We are allowed to initialize repo plugins, so do it!
+ BNInitRepoPlugins();
+ }
}
if !is_license_validated() {
@@ -249,6 +287,14 @@ pub fn license_location() -> Option<LicenseLocation> {
pub struct Session {}
impl Session {
+ /// Get a registered [`Session`] for use.
+ ///
+ /// This is required so that we can keep track of the [`SESSION_COUNT`].
+ fn registered_session() -> Self {
+ let _previous_count = SESSION_COUNT.fetch_add(1, SeqCst);
+ Self {}
+ }
+
/// Before calling new you must make sure that the license is retrievable, otherwise the core won't be able to initialize.
///
/// If you cannot otherwise provide a license via `BN_LICENSE_FILE` environment variable or the Binary Ninja user directory
@@ -257,7 +303,7 @@ impl Session {
if license_location().is_some() {
// We were able to locate a license, continue with initialization.
init()?;
- Ok(Self {})
+ Ok(Self::registered_session())
} else {
// There was no license that could be automatically retrieved, you must call [Self::new_with_license].
Err(InitializationError::NoLicenseFound)
@@ -270,7 +316,7 @@ impl Session {
/// can discover by itself, therefor it is expected that you know where your license is when calling this directly.
pub fn new_with_opts(options: InitializationOptions) -> Result<Self, InitializationError> {
init_with_opts(options)?;
- Ok(Self {})
+ Ok(Self::registered_session())
}
/// ```no_run
@@ -364,6 +410,10 @@ impl Session {
impl Drop for Session {
fn drop(&mut self) {
- shutdown()
+ let previous_count = SESSION_COUNT.fetch_sub(1, SeqCst);
+ if previous_count == 1 {
+ // We were the last session, therefor we can safely shut down.
+ shutdown();
+ }
}
}