cmap.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918
  1. // libcmap interface for Rust
  2. // Copyright (c) 2021 Red Hat, Inc.
  3. //
  4. // All rights reserved.
  5. //
  6. // Author: Christine Caulfield (ccaulfi@redhat.com)
  7. //
  8. #![allow(clippy::type_complexity)]
  9. // For the code generated by bindgen
  10. use crate::sys::cmap as ffi;
  11. use num_enum::TryFromPrimitive;
  12. use std::any::type_name;
  13. use std::collections::HashMap;
  14. use std::convert::TryFrom;
  15. use std::ffi::CString;
  16. use std::fmt;
  17. use std::os::raw::{c_char, c_int, c_void};
  18. use std::ptr::copy_nonoverlapping;
  19. use std::sync::Mutex;
  20. use crate::string_from_bytes;
  21. use crate::{CsError, DispatchFlags, Result};
  22. // Maps:
  23. /// "Maps" available to [initialize]
  24. pub enum Map {
  25. Icmap,
  26. Stats,
  27. }
  28. bitflags! {
  29. /// Tracker types for cmap, both passed into [track_add]
  30. /// and returned from its callback.
  31. pub struct TrackType: i32
  32. {
  33. const DELETE = 1;
  34. const MODIFY = 2;
  35. const ADD = 4;
  36. const PREFIX = 8;
  37. }
  38. }
  39. impl fmt::Display for TrackType {
  40. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  41. if self.contains(TrackType::DELETE) {
  42. write!(f, "DELETE ")?
  43. }
  44. if self.contains(TrackType::MODIFY) {
  45. write!(f, "MODIFY ")?
  46. }
  47. if self.contains(TrackType::ADD) {
  48. write!(f, "ADD ")?
  49. }
  50. if self.contains(TrackType::PREFIX) {
  51. write!(f, "PREFIX ")
  52. } else {
  53. Ok(())
  54. }
  55. }
  56. }
  57. /// A handle returned from [initialize], needs to be passed to all other cmap API calls
  58. pub struct Handle {
  59. cmap_handle: u64,
  60. clone: bool,
  61. }
  62. impl Clone for Handle {
  63. fn clone(&self) -> Handle {
  64. Handle {
  65. cmap_handle: self.cmap_handle,
  66. clone: true,
  67. }
  68. }
  69. }
  70. impl Drop for Handle {
  71. fn drop(self: &mut Handle) {
  72. if !self.clone {
  73. let _e = finalize(self);
  74. }
  75. }
  76. }
  77. // Clones count as equivalent
  78. impl PartialEq for Handle {
  79. fn eq(&self, other: &Handle) -> bool {
  80. self.cmap_handle == other.cmap_handle
  81. }
  82. }
  83. #[derive(Copy, Clone)]
  84. /// A handle for a specific CMAP tracker. returned from [track_add].
  85. /// There may be multiple TrackHandles per [Handle]
  86. pub struct TrackHandle {
  87. track_handle: u64,
  88. notify_callback: NotifyCallback,
  89. }
  90. // Used to convert CMAP handles into one of ours, for callbacks
  91. lazy_static! {
  92. static ref TRACKHANDLE_HASH: Mutex<HashMap<u64, TrackHandle>> = Mutex::new(HashMap::new());
  93. static ref HANDLE_HASH: Mutex<HashMap<u64, Handle>> = Mutex::new(HashMap::new());
  94. }
  95. /// Initialize a connection to the cmap subsystem.
  96. /// map specifies which cmap "map" to use.
  97. /// Returns a [Handle] into the cmap library
  98. pub fn initialize(map: Map) -> Result<Handle> {
  99. let mut handle: ffi::cmap_handle_t = 0;
  100. let c_map = match map {
  101. Map::Icmap => ffi::CMAP_MAP_ICMAP,
  102. Map::Stats => ffi::CMAP_MAP_STATS,
  103. };
  104. unsafe {
  105. let res = ffi::cmap_initialize_map(&mut handle, c_map);
  106. if res == ffi::CS_OK {
  107. let rhandle = Handle {
  108. cmap_handle: handle,
  109. clone: false,
  110. };
  111. HANDLE_HASH.lock().unwrap().insert(handle, rhandle.clone());
  112. Ok(rhandle)
  113. } else {
  114. Err(CsError::from_c(res))
  115. }
  116. }
  117. }
  118. /// Finish with a connection to corosync.
  119. /// Takes a [Handle] as returned from [initialize]
  120. pub fn finalize(handle: &Handle) -> Result<()> {
  121. let res = unsafe { ffi::cmap_finalize(handle.cmap_handle) };
  122. if res == ffi::CS_OK {
  123. HANDLE_HASH.lock().unwrap().remove(&handle.cmap_handle);
  124. Ok(())
  125. } else {
  126. Err(CsError::from_c(res))
  127. }
  128. }
  129. /// Return a file descriptor to use for poll/select on the CMAP handle.
  130. /// Takes a [Handle] as returned from [initialize],
  131. /// returns a C file descriptor as i32
  132. pub fn fd_get(handle: &Handle) -> Result<i32> {
  133. let c_fd: *mut c_int = &mut 0 as *mut _ as *mut c_int;
  134. let res = unsafe { ffi::cmap_fd_get(handle.cmap_handle, c_fd) };
  135. if res == ffi::CS_OK {
  136. Ok(unsafe { *c_fd })
  137. } else {
  138. Err(CsError::from_c(res))
  139. }
  140. }
  141. /// Dispatch any/all active CMAP callbacks.
  142. /// Takes a [Handle] as returned from [initialize],
  143. /// flags [DispatchFlags] tells it how many items to dispatch before returning
  144. pub fn dispatch(handle: &Handle, flags: DispatchFlags) -> Result<()> {
  145. let res = unsafe { ffi::cmap_dispatch(handle.cmap_handle, flags as u32) };
  146. if res == ffi::CS_OK {
  147. Ok(())
  148. } else {
  149. Err(CsError::from_c(res))
  150. }
  151. }
  152. /// Get the current 'context' value for this handle
  153. /// The context value is an arbitrary value that is always passed
  154. /// back to callbacks to help identify the source
  155. pub fn context_get(handle: &Handle) -> Result<u64> {
  156. let (res, context) = unsafe {
  157. let mut context: u64 = 0;
  158. let c_context: *mut c_void = &mut context as *mut _ as *mut c_void;
  159. let r = ffi::cmap_context_get(handle.cmap_handle, c_context as *mut *const c_void);
  160. (r, context)
  161. };
  162. if res == ffi::CS_OK {
  163. Ok(context)
  164. } else {
  165. Err(CsError::from_c(res))
  166. }
  167. }
  168. /// Set the current 'context' value for this handle
  169. /// The context value is an arbitrary value that is always passed
  170. /// back to callbacks to help identify the source.
  171. /// Normally this is set in [initialize], but this allows it to be changed
  172. pub fn context_set(handle: &Handle, context: u64) -> Result<()> {
  173. let res = unsafe {
  174. let c_context = context as *mut c_void;
  175. ffi::cmap_context_set(handle.cmap_handle, c_context)
  176. };
  177. if res == ffi::CS_OK {
  178. Ok(())
  179. } else {
  180. Err(CsError::from_c(res))
  181. }
  182. }
  183. /// The type of data returned from [get] or in a
  184. /// tracker callback or iterator, part of the [Data] struct
  185. #[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
  186. #[repr(u32)]
  187. pub enum DataType {
  188. Int8 = ffi::CMAP_VALUETYPE_INT8,
  189. UInt8 = ffi::CMAP_VALUETYPE_UINT8,
  190. Int16 = ffi::CMAP_VALUETYPE_INT16,
  191. UInt16 = ffi::CMAP_VALUETYPE_UINT16,
  192. Int32 = ffi::CMAP_VALUETYPE_INT32,
  193. UInt32 = ffi::CMAP_VALUETYPE_UINT32,
  194. Int64 = ffi::CMAP_VALUETYPE_INT64,
  195. UInt64 = ffi::CMAP_VALUETYPE_UINT64,
  196. Float = ffi::CMAP_VALUETYPE_FLOAT,
  197. Double = ffi::CMAP_VALUETYPE_DOUBLE,
  198. String = ffi::CMAP_VALUETYPE_STRING,
  199. Binary = ffi::CMAP_VALUETYPE_BINARY,
  200. Unknown = 999,
  201. }
  202. fn cmap_to_enum(cmap_type: u32) -> DataType {
  203. match DataType::try_from(cmap_type) {
  204. Ok(e) => e,
  205. Err(_) => DataType::Unknown,
  206. }
  207. }
  208. /// Data returned from the cmap::get() call and tracker & iterators.
  209. /// Contains the data itself and the type of that data.
  210. pub enum Data {
  211. Int8(i8),
  212. UInt8(u8),
  213. Int16(i16),
  214. UInt16(u16),
  215. Int32(i32),
  216. UInt32(u32),
  217. Int64(i64),
  218. UInt64(u64),
  219. Float(f32),
  220. Double(f64),
  221. String(String),
  222. Binary(Vec<u8>),
  223. Unknown,
  224. }
  225. impl fmt::Display for DataType {
  226. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  227. match self {
  228. DataType::Int8 => write!(f, "Int8"),
  229. DataType::UInt8 => write!(f, "UInt8"),
  230. DataType::Int16 => write!(f, "Int16"),
  231. DataType::UInt16 => write!(f, "UInt16"),
  232. DataType::Int32 => write!(f, "Int32"),
  233. DataType::UInt32 => write!(f, "UInt32"),
  234. DataType::Int64 => write!(f, "Int64"),
  235. DataType::UInt64 => write!(f, "UInt64"),
  236. DataType::Float => write!(f, "Float"),
  237. DataType::Double => write!(f, "Double"),
  238. DataType::String => write!(f, "String"),
  239. DataType::Binary => write!(f, "Binary"),
  240. DataType::Unknown => write!(f, "Unknown"),
  241. }
  242. }
  243. }
  244. impl fmt::Display for Data {
  245. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  246. match self {
  247. Data::Int8(v) => write!(f, "{v} (Int8)"),
  248. Data::UInt8(v) => write!(f, "{v} (UInt8)"),
  249. Data::Int16(v) => write!(f, "{v} (Int16)"),
  250. Data::UInt16(v) => write!(f, "{v} (UInt16)"),
  251. Data::Int32(v) => write!(f, "{v} (Int32)"),
  252. Data::UInt32(v) => write!(f, "{v} (UInt32)"),
  253. Data::Int64(v) => write!(f, "{v} (Int64)"),
  254. Data::UInt64(v) => write!(f, "{v} (UInt64)"),
  255. Data::Float(v) => write!(f, "{v} (Float)"),
  256. Data::Double(v) => write!(f, "{v} (Double)"),
  257. Data::String(v) => write!(f, "{v} (String)"),
  258. Data::Binary(v) => write!(f, "{v:?} (Binary)"),
  259. Data::Unknown => write!(f, "Unknown)"),
  260. }
  261. }
  262. }
  263. const CMAP_KEYNAME_MAXLENGTH: usize = 255;
  264. fn string_to_cstring_validated(key: &str, maxlen: usize) -> Result<CString> {
  265. if maxlen > 0 && key.chars().count() >= maxlen {
  266. return Err(CsError::CsErrInvalidParam);
  267. }
  268. match CString::new(key) {
  269. Ok(n) => Ok(n),
  270. Err(_) => Err(CsError::CsErrLibrary),
  271. }
  272. }
  273. fn set_value(
  274. handle: &Handle,
  275. key_name: &str,
  276. datatype: DataType,
  277. value: *mut c_void,
  278. length: usize,
  279. ) -> Result<()> {
  280. let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
  281. let res = unsafe {
  282. ffi::cmap_set(
  283. handle.cmap_handle,
  284. csname.as_ptr(),
  285. value,
  286. length,
  287. datatype as u32,
  288. )
  289. };
  290. if res == ffi::CS_OK {
  291. Ok(())
  292. } else {
  293. Err(CsError::from_c(res))
  294. }
  295. }
  296. // Returns type and size
  297. fn generic_to_cmap<T>(_value: T) -> (DataType, usize) {
  298. match type_name::<T>() {
  299. "u8" => (DataType::UInt8, 1),
  300. "i8" => (DataType::Int8, 1),
  301. "u16" => (DataType::UInt16, 2),
  302. "i16" => (DataType::Int16, 2),
  303. "u32" => (DataType::UInt32, 4),
  304. "i32" => (DataType::Int32, 4),
  305. "u64" => (DataType::UInt64, 4),
  306. "f32" => (DataType::Float, 4),
  307. "f64" => (DataType::Double, 8),
  308. "&str" => (DataType::String, 0),
  309. // Binary not currently supported here
  310. _ => (DataType::Unknown, 0),
  311. }
  312. }
  313. fn is_numeric_type(dtype: DataType) -> bool {
  314. matches!(
  315. dtype,
  316. DataType::UInt8
  317. | DataType::Int8
  318. | DataType::UInt16
  319. | DataType::Int16
  320. | DataType::UInt32
  321. | DataType::Int32
  322. | DataType::UInt64
  323. | DataType::Int64
  324. | DataType::Float
  325. | DataType::Double
  326. )
  327. }
  328. /// Function to set a generic numeric value
  329. /// This doesn't work for strings or binaries
  330. pub fn set_number<T: Copy>(handle: &Handle, key_name: &str, value: T) -> Result<()> {
  331. let (c_type, c_size) = generic_to_cmap(value);
  332. if is_numeric_type(c_type) {
  333. let mut tmp = value;
  334. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  335. set_value(handle, key_name, c_type, c_value as *mut c_void, c_size)
  336. } else {
  337. Err(CsError::CsErrNotSupported)
  338. }
  339. }
  340. pub fn set_u8(handle: &Handle, key_name: &str, value: u8) -> Result<()> {
  341. let mut tmp = value;
  342. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  343. set_value(handle, key_name, DataType::UInt8, c_value as *mut c_void, 1)
  344. }
  345. /// Sets an i8 value into cmap
  346. pub fn set_i8(handle: &Handle, key_name: &str, value: i8) -> Result<()> {
  347. let mut tmp = value;
  348. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  349. set_value(handle, key_name, DataType::Int8, c_value as *mut c_void, 1)
  350. }
  351. /// Sets a u16 value into cmap
  352. pub fn set_u16(handle: &Handle, key_name: &str, value: u16) -> Result<()> {
  353. let mut tmp = value;
  354. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  355. set_value(
  356. handle,
  357. key_name,
  358. DataType::UInt16,
  359. c_value as *mut c_void,
  360. 2,
  361. )
  362. }
  363. /// Sets an i16 value into cmap
  364. pub fn set_i16(handle: &Handle, key_name: &str, value: i16) -> Result<()> {
  365. let mut tmp = value;
  366. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  367. set_value(handle, key_name, DataType::Int16, c_value as *mut c_void, 2)
  368. }
  369. /// Sets a u32 value into cmap
  370. pub fn set_u32(handle: &Handle, key_name: &str, value: u32) -> Result<()> {
  371. let mut tmp = value;
  372. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  373. set_value(handle, key_name, DataType::UInt32, c_value, 4)
  374. }
  375. /// Sets an i32 value into cmap
  376. pub fn set_i132(handle: &Handle, key_name: &str, value: i32) -> Result<()> {
  377. let mut tmp = value;
  378. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  379. set_value(handle, key_name, DataType::Int32, c_value as *mut c_void, 4)
  380. }
  381. /// Sets a u64 value into cmap
  382. pub fn set_u64(handle: &Handle, key_name: &str, value: u64) -> Result<()> {
  383. let mut tmp = value;
  384. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  385. set_value(
  386. handle,
  387. key_name,
  388. DataType::UInt64,
  389. c_value as *mut c_void,
  390. 8,
  391. )
  392. }
  393. /// Sets an i64 value into cmap
  394. pub fn set_i164(handle: &Handle, key_name: &str, value: i64) -> Result<()> {
  395. let mut tmp = value;
  396. let c_value: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  397. set_value(handle, key_name, DataType::Int64, c_value as *mut c_void, 8)
  398. }
  399. /// Sets a string value into cmap
  400. pub fn set_string(handle: &Handle, key_name: &str, value: &str) -> Result<()> {
  401. let v_string = string_to_cstring_validated(value, 0)?;
  402. set_value(
  403. handle,
  404. key_name,
  405. DataType::String,
  406. v_string.as_ptr() as *mut c_void,
  407. value.chars().count(),
  408. )
  409. }
  410. /// Sets a binary value into cmap
  411. pub fn set_binary(handle: &Handle, key_name: &str, value: &[u8]) -> Result<()> {
  412. set_value(
  413. handle,
  414. key_name,
  415. DataType::Binary,
  416. value.as_ptr() as *mut c_void,
  417. value.len(),
  418. )
  419. }
  420. /// Sets a [Data] type into cmap
  421. pub fn set(handle: &Handle, key_name: &str, data: &Data) -> Result<()> {
  422. let (datatype, datalen, c_value) = match data {
  423. Data::Int8(v) => {
  424. let mut tmp = *v;
  425. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  426. (DataType::Int8, 1, cv)
  427. }
  428. Data::UInt8(v) => {
  429. let mut tmp = *v;
  430. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  431. (DataType::UInt8, 1, cv)
  432. }
  433. Data::Int16(v) => {
  434. let mut tmp = *v;
  435. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  436. (DataType::Int16, 2, cv)
  437. }
  438. Data::UInt16(v) => {
  439. let mut tmp = *v;
  440. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  441. (DataType::UInt8, 2, cv)
  442. }
  443. Data::Int32(v) => {
  444. let mut tmp = *v;
  445. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  446. (DataType::Int32, 4, cv)
  447. }
  448. Data::UInt32(v) => {
  449. let mut tmp = *v;
  450. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  451. (DataType::UInt32, 4, cv)
  452. }
  453. Data::Int64(v) => {
  454. let mut tmp = *v;
  455. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  456. (DataType::Int64, 8, cv)
  457. }
  458. Data::UInt64(v) => {
  459. let mut tmp = *v;
  460. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  461. (DataType::UInt64, 8, cv)
  462. }
  463. Data::Float(v) => {
  464. let mut tmp = *v;
  465. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  466. (DataType::Float, 4, cv)
  467. }
  468. Data::Double(v) => {
  469. let mut tmp = *v;
  470. let cv: *mut c_void = &mut tmp as *mut _ as *mut c_void;
  471. (DataType::Double, 8, cv)
  472. }
  473. Data::String(v) => {
  474. let cv = string_to_cstring_validated(v, 0)?;
  475. // Can't let cv go out of scope
  476. return set_value(
  477. handle,
  478. key_name,
  479. DataType::String,
  480. cv.as_ptr() as *mut c_void,
  481. v.chars().count(),
  482. );
  483. }
  484. Data::Binary(v) => {
  485. // Vec doesn't return quite the right types.
  486. return set_value(
  487. handle,
  488. key_name,
  489. DataType::Binary,
  490. v.as_ptr() as *mut c_void,
  491. v.len(),
  492. );
  493. }
  494. Data::Unknown => return Err(CsError::CsErrInvalidParam),
  495. };
  496. set_value(handle, key_name, datatype, c_value, datalen)
  497. }
  498. // Local function to parse out values from the C mess
  499. // Assumes the c_value is complete. So cmap::get() will need to check the size
  500. // and re-get before calling us with a resized buffer
  501. fn c_to_data(value_size: usize, c_key_type: u32, c_value: *const u8) -> Result<Data> {
  502. unsafe {
  503. match cmap_to_enum(c_key_type) {
  504. DataType::UInt8 => {
  505. let mut ints = [0u8; 1];
  506. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr(), value_size);
  507. Ok(Data::UInt8(ints[0]))
  508. }
  509. DataType::Int8 => {
  510. let mut ints = [0i8; 1];
  511. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  512. Ok(Data::Int8(ints[0]))
  513. }
  514. DataType::UInt16 => {
  515. let mut ints = [0u16; 1];
  516. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  517. Ok(Data::UInt16(ints[0]))
  518. }
  519. DataType::Int16 => {
  520. let mut ints = [0i16; 1];
  521. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  522. Ok(Data::Int16(ints[0]))
  523. }
  524. DataType::UInt32 => {
  525. let mut ints = [0u32; 1];
  526. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  527. Ok(Data::UInt32(ints[0]))
  528. }
  529. DataType::Int32 => {
  530. let mut ints = [0i32; 1];
  531. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  532. Ok(Data::Int32(ints[0]))
  533. }
  534. DataType::UInt64 => {
  535. let mut ints = [0u64; 1];
  536. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  537. Ok(Data::UInt64(ints[0]))
  538. }
  539. DataType::Int64 => {
  540. let mut ints = [0i64; 1];
  541. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  542. Ok(Data::Int64(ints[0]))
  543. }
  544. DataType::Float => {
  545. let mut ints = [0f32; 1];
  546. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  547. Ok(Data::Float(ints[0]))
  548. }
  549. DataType::Double => {
  550. let mut ints = [0f64; 1];
  551. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr() as *mut u8, value_size);
  552. Ok(Data::Double(ints[0]))
  553. }
  554. DataType::String => {
  555. let mut ints = vec![0u8; value_size];
  556. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr(), value_size);
  557. // -1 here so CString doesn't see the NUL
  558. let cs = match CString::new(&ints[0..value_size - 1_usize]) {
  559. Ok(c1) => c1,
  560. Err(_) => return Err(CsError::CsErrLibrary),
  561. };
  562. match cs.into_string() {
  563. Ok(s) => Ok(Data::String(s)),
  564. Err(_) => Err(CsError::CsErrLibrary),
  565. }
  566. }
  567. DataType::Binary => {
  568. let mut ints = vec![0u8; value_size];
  569. copy_nonoverlapping(c_value as *mut u8, ints.as_mut_ptr(), value_size);
  570. Ok(Data::Binary(ints))
  571. }
  572. DataType::Unknown => Ok(Data::Unknown),
  573. }
  574. }
  575. }
  576. const INITIAL_SIZE: usize = 256;
  577. /// Get a value from cmap, returned as a [Data] struct, so could be anything
  578. pub fn get(handle: &Handle, key_name: &str) -> Result<Data> {
  579. let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
  580. let mut value_size: usize = 16;
  581. let mut c_key_type: u32 = 0;
  582. // First guess at a size for Strings and Binaries. Expand if needed
  583. let mut c_value = vec![0u8; INITIAL_SIZE];
  584. unsafe {
  585. let res = ffi::cmap_get(
  586. handle.cmap_handle,
  587. csname.as_ptr(),
  588. c_value.as_mut_ptr() as *mut c_void,
  589. &mut value_size,
  590. &mut c_key_type,
  591. );
  592. if res == ffi::CS_OK {
  593. if value_size > INITIAL_SIZE {
  594. // Need to try again with a bigger buffer
  595. c_value.resize(value_size, 0u8);
  596. let res2 = ffi::cmap_get(
  597. handle.cmap_handle,
  598. csname.as_ptr(),
  599. c_value.as_mut_ptr() as *mut c_void,
  600. &mut value_size,
  601. &mut c_key_type,
  602. );
  603. if res2 != ffi::CS_OK {
  604. return Err(CsError::from_c(res2));
  605. }
  606. }
  607. // Convert to Rust type and return as a Data enum
  608. c_to_data(value_size, c_key_type, c_value.as_ptr())
  609. } else {
  610. Err(CsError::from_c(res))
  611. }
  612. }
  613. }
  614. /// increment the value in a cmap key (must be a numeric type)
  615. pub fn inc(handle: &Handle, key_name: &str) -> Result<()> {
  616. let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
  617. let res = unsafe { ffi::cmap_inc(handle.cmap_handle, csname.as_ptr()) };
  618. if res == ffi::CS_OK {
  619. Ok(())
  620. } else {
  621. Err(CsError::from_c(res))
  622. }
  623. }
  624. /// decrement the value in a cmap key (must be a numeric type)
  625. pub fn dec(handle: &Handle, key_name: &str) -> Result<()> {
  626. let csname = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
  627. let res = unsafe { ffi::cmap_dec(handle.cmap_handle, csname.as_ptr()) };
  628. if res == ffi::CS_OK {
  629. Ok(())
  630. } else {
  631. Err(CsError::from_c(res))
  632. }
  633. }
  634. // Callback for CMAP notify events from corosync, convert params to Rust and pass on.
  635. extern "C" fn rust_notify_fn(
  636. cmap_handle: ffi::cmap_handle_t,
  637. cmap_track_handle: ffi::cmap_track_handle_t,
  638. event: i32,
  639. key_name: *const ::std::os::raw::c_char,
  640. new_value: ffi::cmap_notify_value,
  641. old_value: ffi::cmap_notify_value,
  642. user_data: *mut ::std::os::raw::c_void,
  643. ) {
  644. // If cmap_handle doesn't match then throw away the callback.
  645. if let Some(r_cmap_handle) = HANDLE_HASH.lock().unwrap().get(&cmap_handle) {
  646. if let Some(h) = TRACKHANDLE_HASH.lock().unwrap().get(&cmap_track_handle) {
  647. let r_keyname = match string_from_bytes(key_name, CMAP_KEYNAME_MAXLENGTH) {
  648. Ok(s) => s,
  649. Err(_) => return,
  650. };
  651. let r_old = match c_to_data(old_value.len, old_value.type_, old_value.data as *const u8)
  652. {
  653. Ok(v) => v,
  654. Err(_) => return,
  655. };
  656. let r_new = match c_to_data(new_value.len, new_value.type_, new_value.data as *const u8)
  657. {
  658. Ok(v) => v,
  659. Err(_) => return,
  660. };
  661. if let Some(cb) = h.notify_callback.notify_fn {
  662. (cb)(
  663. r_cmap_handle,
  664. h,
  665. TrackType::from_bits(event).unwrap_or(TrackType::empty()),
  666. &r_keyname,
  667. &r_old,
  668. &r_new,
  669. user_data as u64,
  670. );
  671. }
  672. }
  673. }
  674. }
  675. /// Callback function called every time a tracker reports a change in a tracked value
  676. #[derive(Copy, Clone)]
  677. pub struct NotifyCallback {
  678. pub notify_fn: Option<
  679. fn(
  680. handle: &Handle,
  681. track_handle: &TrackHandle,
  682. event: TrackType,
  683. key_name: &str,
  684. new_value: &Data,
  685. old_value: &Data,
  686. user_data: u64,
  687. ),
  688. >,
  689. }
  690. /// Track changes in cmap values, multiple [TrackHandle]s per [Handle] are allowed
  691. pub fn track_add(
  692. handle: &Handle,
  693. key_name: &str,
  694. track_type: TrackType,
  695. notify_callback: &NotifyCallback,
  696. user_data: u64,
  697. ) -> Result<TrackHandle> {
  698. let c_name = string_to_cstring_validated(key_name, CMAP_KEYNAME_MAXLENGTH)?;
  699. let mut c_trackhandle = 0u64;
  700. let res = unsafe {
  701. ffi::cmap_track_add(
  702. handle.cmap_handle,
  703. c_name.as_ptr(),
  704. track_type.bits(),
  705. Some(rust_notify_fn),
  706. user_data as *mut c_void,
  707. &mut c_trackhandle,
  708. )
  709. };
  710. if res == ffi::CS_OK {
  711. let rhandle = TrackHandle {
  712. track_handle: c_trackhandle,
  713. notify_callback: *notify_callback,
  714. };
  715. TRACKHANDLE_HASH
  716. .lock()
  717. .unwrap()
  718. .insert(c_trackhandle, rhandle);
  719. Ok(rhandle)
  720. } else {
  721. Err(CsError::from_c(res))
  722. }
  723. }
  724. /// Remove a tracker frm this [Handle]
  725. pub fn track_delete(handle: &Handle, track_handle: TrackHandle) -> Result<()> {
  726. let res = unsafe { ffi::cmap_track_delete(handle.cmap_handle, track_handle.track_handle) };
  727. if res == ffi::CS_OK {
  728. TRACKHANDLE_HASH
  729. .lock()
  730. .unwrap()
  731. .remove(&track_handle.track_handle);
  732. Ok(())
  733. } else {
  734. Err(CsError::from_c(res))
  735. }
  736. }
  737. /// Create one of these to start iterating over cmap values.
  738. pub struct CmapIterStart {
  739. iter_handle: u64,
  740. cmap_handle: u64,
  741. }
  742. pub struct CmapIntoIter {
  743. cmap_handle: u64,
  744. iter_handle: u64,
  745. }
  746. /// Value returned from the iterator. contains the key name and the [Data]
  747. pub struct CmapIter {
  748. key_name: String,
  749. data: Data,
  750. }
  751. impl CmapIter {
  752. pub fn key_name(&self) -> &str {
  753. &self.key_name
  754. }
  755. pub fn data(&self) -> &Data {
  756. &self.data
  757. }
  758. }
  759. impl fmt::Debug for CmapIter {
  760. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  761. write!(f, "{}: {}", self.key_name, self.data)
  762. }
  763. }
  764. impl Iterator for CmapIntoIter {
  765. type Item = CmapIter;
  766. fn next(&mut self) -> Option<CmapIter> {
  767. let mut c_key_name = [0u8; CMAP_KEYNAME_MAXLENGTH + 1];
  768. let mut c_value_len = 0usize;
  769. let mut c_value_type = 0u32;
  770. let res = unsafe {
  771. ffi::cmap_iter_next(
  772. self.cmap_handle,
  773. self.iter_handle,
  774. c_key_name.as_mut_ptr() as *mut c_char,
  775. &mut c_value_len,
  776. &mut c_value_type,
  777. )
  778. };
  779. if res == ffi::CS_OK {
  780. // Return the Data for this iteration
  781. let mut c_value = vec![0u8; c_value_len];
  782. let res = unsafe {
  783. ffi::cmap_get(
  784. self.cmap_handle,
  785. c_key_name.as_ptr() as *mut c_char,
  786. c_value.as_mut_ptr() as *mut c_void,
  787. &mut c_value_len,
  788. &mut c_value_type,
  789. )
  790. };
  791. if res == ffi::CS_OK {
  792. match c_to_data(c_value_len, c_value_type, c_value.as_ptr()) {
  793. Ok(d) => {
  794. let r_keyname = match string_from_bytes(
  795. c_key_name.as_ptr() as *mut c_char,
  796. CMAP_KEYNAME_MAXLENGTH,
  797. ) {
  798. Ok(s) => s,
  799. Err(_) => return None,
  800. };
  801. Some(CmapIter {
  802. key_name: r_keyname,
  803. data: d,
  804. })
  805. }
  806. Err(_) => None,
  807. }
  808. } else {
  809. // cmap_get returned error
  810. None
  811. }
  812. } else if res == ffi::CS_ERR_NO_SECTIONS {
  813. // End of list
  814. unsafe {
  815. // Yeah, we don't check this return code. There's nowhere to report it.
  816. ffi::cmap_iter_finalize(self.cmap_handle, self.iter_handle)
  817. };
  818. None
  819. } else {
  820. None
  821. }
  822. }
  823. }
  824. impl CmapIterStart {
  825. /// Create a new [CmapIterStart] object for iterating over a list of cmap keys
  826. pub fn new(cmap_handle: &Handle, prefix: &str) -> Result<CmapIterStart> {
  827. let mut iter_handle: u64 = 0;
  828. let res = unsafe {
  829. let c_prefix = string_to_cstring_validated(prefix, CMAP_KEYNAME_MAXLENGTH)?;
  830. ffi::cmap_iter_init(cmap_handle.cmap_handle, c_prefix.as_ptr(), &mut iter_handle)
  831. };
  832. if res == ffi::CS_OK {
  833. Ok(CmapIterStart {
  834. cmap_handle: cmap_handle.cmap_handle,
  835. iter_handle,
  836. })
  837. } else {
  838. Err(CsError::from_c(res))
  839. }
  840. }
  841. }
  842. impl IntoIterator for CmapIterStart {
  843. type Item = CmapIter;
  844. type IntoIter = CmapIntoIter;
  845. fn into_iter(self) -> Self::IntoIter {
  846. CmapIntoIter {
  847. iter_handle: self.iter_handle,
  848. cmap_handle: self.cmap_handle,
  849. }
  850. }
  851. }