Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bindings: add rust bindings #78

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions bindings/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "swupdate-bindings"
version = "0.1.0"
edition = "2021"

[dependencies]
lazy_static = "1.4.0"
libc = "0.2.147"
once_cell = "1.18.0"
139 changes: 139 additions & 0 deletions bindings/rust/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
use lazy_static::lazy_static;
use once_cell::sync::OnceCell;
use std::ffi::{CStr, CString};
use std::io::{Error, ErrorKind};
use std::os::raw::{c_char, c_int};
use std::sync::{Condvar, Mutex};

mod types;
use types::{
ipc_message::IpcMessage, run_type::RunType, source_type::SourceType,
swupdate_request::SwupdateRequest,
};

type WriteData = unsafe extern "C" fn(*mut *mut c_char, *mut c_int) -> c_int;
type GetStatus = unsafe extern "C" fn(*mut IpcMessage) -> c_int;
type Terminated = unsafe extern "C" fn(c_int) -> c_int;
type Callback = fn(String);

lazy_static! {
static ref MY_MUTEX: Mutex<bool> = Mutex::new(false);
static ref CV_END: Condvar = Condvar::new();
}

static mut FD: c_int = 0;
static mut BUF: [u8; 256] = [0u8; 256];
static mut CB: OnceCell<Callback> = OnceCell::new();

#[link(name = "swupdate")]
extern "C" {
fn swupdate_async_start(
wr_func: WriteData,
status_func: GetStatus,
end_func: Terminated,
req: *mut SwupdateRequest,
size: isize,
) -> c_int;

fn swupdate_prepare_req(req: *mut SwupdateRequest);
}

extern "C" fn readimage(p: *mut *mut c_char, size: *mut c_int) -> c_int {
unsafe {
let ret = libc::read(FD, BUF.as_mut_ptr() as *mut std::ffi::c_void, BUF.len());

*p = BUF.as_mut_ptr() as *mut c_char;
*size = ret as c_int;

ret as c_int
}
}

extern "C" fn printstatus(msg: *mut IpcMessage) -> c_int {
unsafe {
CB.get().expect("Callback not initialized")(format!(
"Status: {:?} message: {:?}\n",
(*msg).data.status.current,
CStr::from_ptr((*msg).data.status.desc.as_ptr())
));
};
0
}

extern "C" fn end(_status: c_int) -> c_int {
let mut guard = MY_MUTEX.lock().unwrap();
*guard = true;
CV_END.notify_one();

0
}

fn open_file(filename: &str) -> c_int {
let c_filename = CString::new(filename).expect("CString::new failed");
unsafe {
let fd = libc::open(c_filename.as_ptr(), libc::O_RDONLY);
if fd < 0 {
eprintln!("Unable to open {}", filename);
return libc::EXIT_FAILURE;
}
FD = fd;
}
libc::EXIT_SUCCESS
}

fn close_file() {
unsafe {
if FD >= 0 {
libc::close(FD);
}
}
}

pub fn send_file(filename: &str, dry_run: bool, cb: Callback) -> Result<(), Error> {
open_file(filename);

let dry_run_val = if dry_run {
RunType::Dryrun
} else {
RunType::Default
};

let mut req = SwupdateRequest {
apiversion: 0,
source: SourceType::Local,
dry_run: dry_run_val,
len: 0,
info: [0; 512],
software_set: [0; 256],
running_mode: [0; 256],
disable_store_swu: false,
};

unsafe { swupdate_prepare_req(&mut req) };

let mut guard = MY_MUTEX.lock().unwrap();

unsafe {
let size = std::mem::size_of_val(&req).try_into().unwrap();
CB.get_or_init(|| cb);
let rc = swupdate_async_start(readimage, printstatus, end, &mut req, size);
if rc < 0 {
close_file();
return Err(Error::new(
ErrorKind::Other,
format!(
"Software update failed to start with return code: {:?}",
libc::EXIT_FAILURE
),
));
}
}

while !*guard {
guard = CV_END.wait(guard).unwrap();
}

close_file();

Ok(())
}
87 changes: 87 additions & 0 deletions bindings/rust/types/ipc_message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use std::os::raw::{c_char, c_int, c_uint};

use crate::types::source_type::SourceType;
use crate::SwupdateRequest;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct Status {
pub current: c_int,
last_result: c_int,
error: c_int,
pub desc: [c_char; 2048],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct Notify {
status: c_int,
error: c_int,
level: c_int,
msg: [c_char; 2048],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct InstMsg {
req: SwupdateRequest,
len: c_uint,
buf: [c_char; 2048],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct ProcMsg {
source: SourceType,
cmd: c_int,
timeout: c_int,
len: c_uint,
buf: [c_char; 2048],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct AESKeyMsg {
key_ascii: [c_char; 65],
ivt_ascii: [c_char; 33],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct Versions {
minimum_version: [c_char; 256],
maximum_version: [c_char; 256],
current_version: [c_char; 256],
}

#[repr(C)]
#[derive(Clone, Copy)]
struct Revisions {
boardname: [c_char; 256],
revision: [c_char; 256],
}

#[repr(C)]
pub union MsgData {
msg: [c_char; 128],
pub status: Status,
notify: Notify,
inst_msg: InstMsg,
proc_msg: ProcMsg,
aes_key_msg: AESKeyMsg,
versions: Versions,
revisions: Revisions,
}

impl Default for MsgData {
fn default() -> Self {
MsgData { msg: [0; 128] }
}
}

#[repr(C)]
pub struct IpcMessage {
magic: c_int,
type_: c_int,
pub data: MsgData,
}
4 changes: 4 additions & 0 deletions bindings/rust/types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod ipc_message;
pub mod run_type;
pub mod source_type;
pub mod swupdate_request;
7 changes: 7 additions & 0 deletions bindings/rust/types/run_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[repr(C)]
#[derive(Clone, Copy)]
pub enum RunType {
Default,
Dryrun,
_Install,
}
10 changes: 10 additions & 0 deletions bindings/rust/types/source_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#[repr(C)]
#[derive(Clone, Copy)]
pub enum SourceType {
_Unknown,
_Webserver,
_Suricatta,
_Downloader,
Local,
_ChunksDownloader,
}
16 changes: 16 additions & 0 deletions bindings/rust/types/swupdate_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::os::raw::c_char;

use crate::types::{run_type::RunType, source_type::SourceType};

#[repr(C)]
#[derive(Clone, Copy)]
pub struct SwupdateRequest {
pub apiversion: u32,
pub source: SourceType,
pub dry_run: RunType,
pub len: usize,
pub info: [c_char; 512],
pub software_set: [c_char; 256],
pub running_mode: [c_char; 256],
pub disable_store_swu: bool,
}