lib.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. //! This crate provides access to the corosync libraries cpg, cfg, cmap, quorum & votequorum
  2. //! from Rust. They are a fairly thin layer around the actual API calls but with Rust data types
  3. //! and iterators.
  4. //!
  5. //! Corosync is a low-level provider of cluster services for high-availability clusters,
  6. //! for more information about corosync see <https://corosync.github.io/corosync/>
  7. //!
  8. //! No more information about corosync itself will be provided here, it is expected that if
  9. //! you feel you need access to the Corosync API calls, you know what they do :)
  10. //!
  11. //! # Example
  12. //! ```
  13. //! extern crate rust_corosync as corosync;
  14. //! use corosync::cmap;
  15. //!
  16. //! fn main()
  17. //! {
  18. //! // Open connection to corosync libcmap
  19. //! let handle =
  20. //! match cmap::initialize(cmap::Map::Icmap) {
  21. //! Ok(h) => {
  22. //! println!("cmap initialized.");
  23. //! h
  24. //! }
  25. //! Err(e) => {
  26. //! println!("Error in CMAP (Icmap) init: {}", e);
  27. //! return;
  28. //! }
  29. //! };
  30. //!
  31. //! // Set a numeric value (this is a generic fn)
  32. //! match cmap::set_number(handle, "test.test_uint32", 456)
  33. //! {
  34. //! Ok(_) => {}
  35. //! Err(e) => {
  36. //! println!("Error in CMAP set_u32: {}", e);
  37. //! return;
  38. //! }
  39. //! };
  40. //!
  41. //! // Get a value - this will be a Data struct
  42. //! match cmap::get(handle, "test.test_uint32")
  43. //! {
  44. //! Ok(v) => {
  45. //! println!("GOT value {}", v);
  46. //! }
  47. //! Err(e) => {
  48. //! println!("Error in CMAP get: {}", e);
  49. //! return;
  50. //! }
  51. //! };
  52. //!
  53. //! // Use an iterator
  54. //! match cmap::CmapIterStart::new(handle, "totem.") {
  55. //! Ok(cmap_iter) => {
  56. //! for i in cmap_iter {
  57. //! println!("ITER: {:?}", i);
  58. //! }
  59. //! println!("");
  60. //! }
  61. //! Err(e) => {
  62. //! println!("Error in CMAP iter start: {}", e);
  63. //! }
  64. //! }
  65. //!
  66. //! // Close this connection
  67. //! match cmap::finalize(handle)
  68. //! {
  69. //! Ok(_) => {}
  70. //! Err(e) => {
  71. //! println!("Error in CMAP get: {}", e);
  72. //! return;
  73. //! }
  74. //! };
  75. //! }
  76. #[macro_use]
  77. extern crate lazy_static;
  78. #[macro_use]
  79. extern crate bitflags;
  80. /// cfg is the internal configuration and information library for corosync, it is
  81. /// mainly used by internal tools but may also contain API calls useful to some applications
  82. /// that need detailed information about or control of the operation of corosync and the cluster.
  83. pub mod cfg;
  84. /// cmap is the internal 'database' of corosync - though it is NOT replicated. Mostly it contains
  85. /// a copy of the corosync.conf file and information about the running state of the daemon.
  86. /// The cmap API provides two 'maps'. Icmap, which is as above, and Stats, which contains very detailed
  87. /// statistics on the running system, this includes network and IPC calls.
  88. pub mod cmap;
  89. /// cpg is the Control Process Groups subsystem of corosync and is usually used for sending
  90. /// messages around the cluster. All processes using CPG belong to a named group (whose members
  91. /// they can query) and all messages are sent with delivery guarantees.
  92. pub mod cpg;
  93. /// Quorum provides basic information about the quorate state of the cluster with callbacks
  94. /// when nodelists change.
  95. pub mod quorum;
  96. ///votequorum is the main quorum provider for corosync, using this API, users can query the state
  97. /// of nodes in the cluster, request callbacks when the nodelists change, and set up a quorum device.
  98. pub mod votequorum;
  99. mod sys;
  100. use num_enum::TryFromPrimitive;
  101. use std::convert::TryFrom;
  102. use std::error::Error;
  103. use std::ffi::CString;
  104. use std::fmt;
  105. use std::ptr::copy_nonoverlapping;
  106. // This needs to be kept up-to-date!
  107. /// Error codes returned from the corosync libraries
  108. #[derive(Debug, Eq, PartialEq, Copy, Clone, TryFromPrimitive)]
  109. #[repr(u32)]
  110. pub enum CsError {
  111. CsOk = 1,
  112. CsErrLibrary = 2,
  113. CsErrVersion = 3,
  114. CsErrInit = 4,
  115. CsErrTimeout = 5,
  116. CsErrTryAgain = 6,
  117. CsErrInvalidParam = 7,
  118. CsErrNoMemory = 8,
  119. CsErrBadHandle = 9,
  120. CsErrBusy = 10,
  121. CsErrAccess = 11,
  122. CsErrNotExist = 12,
  123. CsErrNameTooLong = 13,
  124. CsErrExist = 14,
  125. CsErrNoSpace = 15,
  126. CsErrInterrupt = 16,
  127. CsErrNameNotFound = 17,
  128. CsErrNoResources = 18,
  129. CsErrNotSupported = 19,
  130. CsErrBadOperation = 20,
  131. CsErrFailedOperation = 21,
  132. CsErrMessageError = 22,
  133. CsErrQueueFull = 23,
  134. CsErrQueueNotAvailable = 24,
  135. CsErrBadFlags = 25,
  136. CsErrTooBig = 26,
  137. CsErrNoSection = 27,
  138. CsErrContextNotFound = 28,
  139. CsErrTooManyGroups = 30,
  140. CsErrSecurity = 100,
  141. #[num_enum(default)]
  142. CsErrRustCompat = 998, // Set if we get a unknown return from corosync
  143. CsErrRustString = 999, // Set if we get a string conversion error
  144. }
  145. /// Result type returned from most corosync library calls.
  146. /// Contains a [CsError] and possibly other data as required
  147. pub type Result<T> = ::std::result::Result<T, CsError>;
  148. impl fmt::Display for CsError {
  149. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  150. match self {
  151. CsError::CsOk => write!(f, "OK"),
  152. CsError::CsErrLibrary => write!(f, "ErrLibrary"),
  153. CsError::CsErrVersion => write!(f, "ErrVersion"),
  154. CsError::CsErrInit => write!(f, "ErrInit"),
  155. CsError::CsErrTimeout => write!(f, "ErrTimeout"),
  156. CsError::CsErrTryAgain => write!(f, "ErrTryAgain"),
  157. CsError::CsErrInvalidParam => write!(f, "ErrInvalidParam"),
  158. CsError::CsErrNoMemory => write!(f, "ErrNoMemory"),
  159. CsError::CsErrBadHandle => write!(f, "ErrbadHandle"),
  160. CsError::CsErrBusy => write!(f, "ErrBusy"),
  161. CsError::CsErrAccess => write!(f, "ErrAccess"),
  162. CsError::CsErrNotExist => write!(f, "ErrNotExist"),
  163. CsError::CsErrNameTooLong => write!(f, "ErrNameTooLong"),
  164. CsError::CsErrExist => write!(f, "ErrExist"),
  165. CsError::CsErrNoSpace => write!(f, "ErrNoSpace"),
  166. CsError::CsErrInterrupt => write!(f, "ErrInterrupt"),
  167. CsError::CsErrNameNotFound => write!(f, "ErrNameNotFound"),
  168. CsError::CsErrNoResources => write!(f, "ErrNoResources"),
  169. CsError::CsErrNotSupported => write!(f, "ErrNotSupported"),
  170. CsError::CsErrBadOperation => write!(f, "ErrBadOperation"),
  171. CsError::CsErrFailedOperation => write!(f, "ErrFailedOperation"),
  172. CsError::CsErrMessageError => write!(f, "ErrMEssageError"),
  173. CsError::CsErrQueueFull => write!(f, "ErrQueueFull"),
  174. CsError::CsErrQueueNotAvailable => write!(f, "ErrQueueNotAvailable"),
  175. CsError::CsErrBadFlags => write!(f, "ErrBadFlags"),
  176. CsError::CsErrTooBig => write!(f, "ErrTooBig"),
  177. CsError::CsErrNoSection => write!(f, "ErrNoSection"),
  178. CsError::CsErrContextNotFound => write!(f, "ErrContextNotFound"),
  179. CsError::CsErrTooManyGroups => write!(f, "ErrTooManyGroups"),
  180. CsError::CsErrSecurity => write!(f, "ErrSecurity"),
  181. CsError::CsErrRustCompat => write!(f, "ErrRustCompat"),
  182. CsError::CsErrRustString => write!(f, "ErrRustString"),
  183. }
  184. }
  185. }
  186. impl Error for CsError {}
  187. // This is dependant on the num_enum crate, converts a C cs_error_t into the Rust enum
  188. // There seems to be some debate as to whether this should be part of the language:
  189. // https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/25
  190. impl CsError {
  191. fn from_c(cserr: u32) -> CsError {
  192. match CsError::try_from(cserr) {
  193. Ok(e) => e,
  194. Err(_) => CsError::CsErrRustCompat,
  195. }
  196. }
  197. }
  198. /// Flags to use with dispatch functions, eg [cpg::dispatch]
  199. /// One will dispatch a single callback (blocking) and return.
  200. /// All will loop trying to dispatch all possible callbacks.
  201. /// Blocking is like All but will block between callbacks.
  202. /// OneNonBlocking will dispatch a single callback only if one is available,
  203. /// otherwise it will return even if no callback is available.
  204. #[derive(Copy, Clone)]
  205. // The numbers match the C enum, of course.
  206. pub enum DispatchFlags {
  207. One = 1,
  208. All = 2,
  209. Blocking = 3,
  210. OneNonblocking = 4,
  211. }
  212. /// Flags to use with (most) tracking API calls
  213. #[derive(Copy, Clone)]
  214. // Same here
  215. pub enum TrackFlags {
  216. Current = 1,
  217. Changes = 2,
  218. ChangesOnly = 4,
  219. }
  220. /// A corosync nodeid
  221. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  222. pub struct NodeId {
  223. id: u32,
  224. }
  225. impl fmt::Display for NodeId {
  226. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  227. write!(f, "{}", self.id)
  228. }
  229. }
  230. // Conversion from a NodeId to and from u32
  231. impl From<u32> for NodeId {
  232. fn from(id: u32) -> NodeId {
  233. NodeId { id }
  234. }
  235. }
  236. impl From<NodeId> for u32 {
  237. fn from(nodeid: NodeId) -> u32 {
  238. nodeid.id
  239. }
  240. }
  241. // General internal routine to copy bytes from a C array into a Rust String
  242. fn string_from_bytes(bytes: *const ::std::os::raw::c_char, max_length: usize) -> Result<String> {
  243. let mut newbytes = vec![0u8; max_length];
  244. // Get length of the string in old-fashioned style
  245. let mut length: usize = 0;
  246. let mut count = 0;
  247. let mut tmpbytes = bytes;
  248. while count < max_length || length == 0 {
  249. if unsafe { *tmpbytes } == 0 && length == 0 {
  250. length = count;
  251. break;
  252. }
  253. count += 1;
  254. tmpbytes = unsafe { tmpbytes.offset(1) }
  255. }
  256. // Cope with an empty string
  257. if length == 0 {
  258. return Ok(String::new());
  259. }
  260. unsafe {
  261. // We need to fully copy it, not shallow copy it.
  262. // Messy casting on both parts of the copy here to get it to work on both signed
  263. // and unsigned char machines
  264. copy_nonoverlapping(bytes as *mut i8, newbytes.as_mut_ptr() as *mut i8, length);
  265. }
  266. let cs = match CString::new(&newbytes[0..length]) {
  267. Ok(c1) => c1,
  268. Err(_) => return Err(CsError::CsErrRustString),
  269. };
  270. // This is just to convert the error type
  271. match cs.into_string() {
  272. Ok(s) => Ok(s),
  273. Err(_) => Err(CsError::CsErrRustString),
  274. }
  275. }