| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- //! This crate provides access to the corosync libraries cpg, cfg, cmap, quorum & votequorum
- //! from Rust. They are a fairly thin layer around the actual API calls but with Rust data types
- //! and iterators.
- //!
- //! Corosync is a low-level provider of cluster services for high-availability clusters,
- //! for more information about corosync see <https://corosync.github.io/corosync/>
- //!
- //! No more information about corosync itself will be provided here, it is expected that if
- //! you feel you need access to the Corosync API calls, you know what they do :)
- //!
- //! # Example
- //! ```
- //! extern crate rust_corosync as corosync;
- //! use corosync::cmap;
- //!
- //! fn main()
- //! {
- //! // Open connection to corosync libcmap
- //! let handle =
- //! match cmap::initialize(cmap::Map::Icmap) {
- //! Ok(h) => {
- //! println!("cmap initialized.");
- //! h
- //! }
- //! Err(e) => {
- //! println!("Error in CMAP (Icmap) init: {}", e);
- //! return;
- //! }
- //! };
- //!
- //! // Set a numeric value (this is a generic fn)
- //! match cmap::set_number(handle, "test.test_uint32", 456)
- //! {
- //! Ok(_) => {}
- //! Err(e) => {
- //! println!("Error in CMAP set_u32: {}", e);
- //! return;
- //! }
- //! };
- //!
- //! // Get a value - this will be a Data struct
- //! match cmap::get(handle, "test.test_uint32")
- //! {
- //! Ok(v) => {
- //! println!("GOT value {}", v);
- //! }
- //! Err(e) => {
- //! println!("Error in CMAP get: {}", e);
- //! return;
- //! }
- //! };
- //!
- //! // Use an iterator
- //! match cmap::CmapIterStart::new(handle, "totem.") {
- //! Ok(cmap_iter) => {
- //! for i in cmap_iter {
- //! println!("ITER: {:?}", i);
- //! }
- //! println!("");
- //! }
- //! Err(e) => {
- //! println!("Error in CMAP iter start: {}", e);
- //! }
- //! }
- //!
- //! // Close this connection
- //! match cmap::finalize(handle)
- //! {
- //! Ok(_) => {}
- //! Err(e) => {
- //! println!("Error in CMAP get: {}", e);
- //! return;
- //! }
- //! };
- //! }
- #[macro_use]
- extern crate lazy_static;
- #[macro_use]
- extern crate bitflags;
- /// cfg is the internal configuration and information library for corosync, it is
- /// mainly used by internal tools but may also contain API calls useful to some applications
- /// that need detailed information about or control of the operation of corosync and the cluster.
- pub mod cfg;
- /// cmap is the internal 'database' of corosync - though it is NOT replicated. Mostly it contains
- /// a copy of the corosync.conf file and information about the running state of the daemon.
- /// The cmap API provides two 'maps'. Icmap, which is as above, and Stats, which contains very detailed
- /// statistics on the running system, this includes network and IPC calls.
- pub mod cmap;
- /// cpg is the Control Process Groups subsystem of corosync and is usually used for sending
- /// messages around the cluster. All processes using CPG belong to a named group (whose members
- /// they can query) and all messages are sent with delivery guarantees.
- pub mod cpg;
- /// Quorum provides basic information about the quorate state of the cluster with callbacks
- /// when nodelists change.
- pub mod quorum;
- ///votequorum is the main quorum provider for corosync, using this API, users can query the state
- /// of nodes in the cluster, request callbacks when the nodelists change, and set up a quorum device.
- pub mod votequorum;
- mod sys;
- use num_enum::TryFromPrimitive;
- use std::convert::TryFrom;
- use std::error::Error;
- use std::ffi::CString;
- use std::fmt;
- use std::ptr::copy_nonoverlapping;
- // This needs to be kept up-to-date!
- /// Error codes returned from the corosync libraries
- #[derive(Debug, Eq, PartialEq, Copy, Clone, TryFromPrimitive)]
- #[repr(u32)]
- pub enum CsError {
- CsOk = 1,
- CsErrLibrary = 2,
- CsErrVersion = 3,
- CsErrInit = 4,
- CsErrTimeout = 5,
- CsErrTryAgain = 6,
- CsErrInvalidParam = 7,
- CsErrNoMemory = 8,
- CsErrBadHandle = 9,
- CsErrBusy = 10,
- CsErrAccess = 11,
- CsErrNotExist = 12,
- CsErrNameTooLong = 13,
- CsErrExist = 14,
- CsErrNoSpace = 15,
- CsErrInterrupt = 16,
- CsErrNameNotFound = 17,
- CsErrNoResources = 18,
- CsErrNotSupported = 19,
- CsErrBadOperation = 20,
- CsErrFailedOperation = 21,
- CsErrMessageError = 22,
- CsErrQueueFull = 23,
- CsErrQueueNotAvailable = 24,
- CsErrBadFlags = 25,
- CsErrTooBig = 26,
- CsErrNoSection = 27,
- CsErrContextNotFound = 28,
- CsErrTooManyGroups = 30,
- CsErrSecurity = 100,
- #[num_enum(default)]
- CsErrRustCompat = 998, // Set if we get a unknown return from corosync
- CsErrRustString = 999, // Set if we get a string conversion error
- }
- /// Result type returned from most corosync library calls.
- /// Contains a [CsError] and possibly other data as required
- pub type Result<T> = ::std::result::Result<T, CsError>;
- impl fmt::Display for CsError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- CsError::CsOk => write!(f, "OK"),
- CsError::CsErrLibrary => write!(f, "ErrLibrary"),
- CsError::CsErrVersion => write!(f, "ErrVersion"),
- CsError::CsErrInit => write!(f, "ErrInit"),
- CsError::CsErrTimeout => write!(f, "ErrTimeout"),
- CsError::CsErrTryAgain => write!(f, "ErrTryAgain"),
- CsError::CsErrInvalidParam => write!(f, "ErrInvalidParam"),
- CsError::CsErrNoMemory => write!(f, "ErrNoMemory"),
- CsError::CsErrBadHandle => write!(f, "ErrbadHandle"),
- CsError::CsErrBusy => write!(f, "ErrBusy"),
- CsError::CsErrAccess => write!(f, "ErrAccess"),
- CsError::CsErrNotExist => write!(f, "ErrNotExist"),
- CsError::CsErrNameTooLong => write!(f, "ErrNameTooLong"),
- CsError::CsErrExist => write!(f, "ErrExist"),
- CsError::CsErrNoSpace => write!(f, "ErrNoSpace"),
- CsError::CsErrInterrupt => write!(f, "ErrInterrupt"),
- CsError::CsErrNameNotFound => write!(f, "ErrNameNotFound"),
- CsError::CsErrNoResources => write!(f, "ErrNoResources"),
- CsError::CsErrNotSupported => write!(f, "ErrNotSupported"),
- CsError::CsErrBadOperation => write!(f, "ErrBadOperation"),
- CsError::CsErrFailedOperation => write!(f, "ErrFailedOperation"),
- CsError::CsErrMessageError => write!(f, "ErrMEssageError"),
- CsError::CsErrQueueFull => write!(f, "ErrQueueFull"),
- CsError::CsErrQueueNotAvailable => write!(f, "ErrQueueNotAvailable"),
- CsError::CsErrBadFlags => write!(f, "ErrBadFlags"),
- CsError::CsErrTooBig => write!(f, "ErrTooBig"),
- CsError::CsErrNoSection => write!(f, "ErrNoSection"),
- CsError::CsErrContextNotFound => write!(f, "ErrContextNotFound"),
- CsError::CsErrTooManyGroups => write!(f, "ErrTooManyGroups"),
- CsError::CsErrSecurity => write!(f, "ErrSecurity"),
- CsError::CsErrRustCompat => write!(f, "ErrRustCompat"),
- CsError::CsErrRustString => write!(f, "ErrRustString"),
- }
- }
- }
- impl Error for CsError {}
- // This is dependant on the num_enum crate, converts a C cs_error_t into the Rust enum
- // There seems to be some debate as to whether this should be part of the language:
- // https://internals.rust-lang.org/t/pre-rfc-enum-from-integer/6348/25
- impl CsError {
- fn from_c(cserr: u32) -> CsError {
- match CsError::try_from(cserr) {
- Ok(e) => e,
- Err(_) => CsError::CsErrRustCompat,
- }
- }
- }
- /// Flags to use with dispatch functions, eg [cpg::dispatch]
- /// One will dispatch a single callback (blocking) and return.
- /// All will loop trying to dispatch all possible callbacks.
- /// Blocking is like All but will block between callbacks.
- /// OneNonBlocking will dispatch a single callback only if one is available,
- /// otherwise it will return even if no callback is available.
- #[derive(Copy, Clone)]
- // The numbers match the C enum, of course.
- pub enum DispatchFlags {
- One = 1,
- All = 2,
- Blocking = 3,
- OneNonblocking = 4,
- }
- /// Flags to use with (most) tracking API calls
- #[derive(Copy, Clone)]
- // Same here
- pub enum TrackFlags {
- Current = 1,
- Changes = 2,
- ChangesOnly = 4,
- }
- /// A corosync nodeid
- #[derive(Copy, Clone, Debug, PartialEq, Eq)]
- pub struct NodeId {
- id: u32,
- }
- impl fmt::Display for NodeId {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", self.id)
- }
- }
- // Conversion from a NodeId to and from u32
- impl From<u32> for NodeId {
- fn from(id: u32) -> NodeId {
- NodeId { id }
- }
- }
- impl From<NodeId> for u32 {
- fn from(nodeid: NodeId) -> u32 {
- nodeid.id
- }
- }
- // General internal routine to copy bytes from a C array into a Rust String
- fn string_from_bytes(bytes: *const ::std::os::raw::c_char, max_length: usize) -> Result<String> {
- let mut newbytes = vec![0u8; max_length];
- // Get length of the string in old-fashioned style
- let mut length: usize = 0;
- let mut count = 0;
- let mut tmpbytes = bytes;
- while count < max_length || length == 0 {
- if unsafe { *tmpbytes } == 0 && length == 0 {
- length = count;
- break;
- }
- count += 1;
- tmpbytes = unsafe { tmpbytes.offset(1) }
- }
- // Cope with an empty string
- if length == 0 {
- return Ok(String::new());
- }
- unsafe {
- // We need to fully copy it, not shallow copy it.
- // Messy casting on both parts of the copy here to get it to work on both signed
- // and unsigned char machines
- copy_nonoverlapping(bytes as *mut i8, newbytes.as_mut_ptr() as *mut i8, length);
- }
- let cs = match CString::new(&newbytes[0..length]) {
- Ok(c1) => c1,
- Err(_) => return Err(CsError::CsErrRustString),
- };
- // This is just to convert the error type
- match cs.into_string() {
- Ok(s) => Ok(s),
- Err(_) => Err(CsError::CsErrRustString),
- }
- }
|