summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am66
-rw-r--r--lib/Makefile.in786
-rw-r--r--lib/cfg.c835
-rw-r--r--lib/cmap.c1119
-rw-r--r--lib/cpg.c1426
-rw-r--r--lib/libcfg.versions18
-rw-r--r--lib/libcfg.verso1
-rw-r--r--lib/libcmap.versions6
-rw-r--r--lib/libcmap.verso1
-rw-r--r--lib/libcpg.versions17
-rw-r--r--lib/libcpg.verso1
-rw-r--r--lib/libquorum.versions11
-rw-r--r--lib/libquorum.verso1
-rw-r--r--lib/libsam.versions12
-rw-r--r--lib/libsam.verso1
-rw-r--r--lib/libvotequorum.versions17
-rw-r--r--lib/libvotequorum.verso1
-rw-r--r--lib/quorum.c588
-rw-r--r--lib/sam.c1489
-rw-r--r--lib/util.h54
-rw-r--r--lib/votequorum.c811
21 files changed, 7261 insertions, 0 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
new file mode 100644
index 0000000..002866a
--- /dev/null
+++ b/lib/Makefile.am
@@ -0,0 +1,66 @@
+#
+# Copyright (c) 2009-2020 Red Hat, Inc.
+#
+# Authors: Andrew Beekhof
+# Steven Dake (sdake@redhat.com)
+#
+# This software licensed under BSD license, the text of which follows:
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Functions to be used at link time (target.lo)
+get_libname=$(shell echo $1 | $(SED) -e "s/\.lo//")
+uc=$(shell echo $(call get_libname,$1) | tr a-z A-Z)
+get_soname=$(subst .,:,$(if $($(call uc,$1)_SONAME),$($(call uc,$1)_SONAME),$(SONAME)))
+get_major=$(firstword $(subst :, ,$(call get_soname,$1)))
+
+MAINTAINERCLEANFILES = Makefile.in
+
+EXTRA_DIST = libcfg.versions libcfg.verso \
+ libcmap.versions libcmap.verso \
+ libcpg.versions libcpg.verso \
+ libquorum.versions libquorum.verso \
+ libsam.versions libsam.verso \
+ libvotequorum.versions libvotequorum.verso
+
+noinst_HEADERS = util.h
+
+# override global LIBS that pulls in lots of craft we don't need here
+LIBS = -version-number $(call get_soname,$<) \
+ @VERSCRIPT_LDFLAGS@ \
+ -lpthread \
+ $(top_builddir)/common_lib/libcorosync_common.la \
+ $(LIBQB_LIBS)
+
+lib_LTLIBRARIES = libcpg.la libquorum.la libcfg.la \
+ libvotequorum.la libcmap.la libsam.la
+
+libcpg_la_SOURCES = cpg.c
+libcfg_la_SOURCES = cfg.c
+libquorum_la_SOURCES = quorum.c
+libvotequorum_la_SOURCES= votequorum.c
+libcmap_la_SOURCES = cmap.c
+libsam_la_SOURCES = sam.c
+libsam_la_LIBADD = libquorum.la libcmap.la
diff --git a/lib/Makefile.in b/lib/Makefile.in
new file mode 100644
index 0000000..2fa4309
--- /dev/null
+++ b/lib/Makefile.in
@@ -0,0 +1,786 @@
+# Makefile.in generated by automake 1.13.4 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright (c) 2009-2020 Red Hat, Inc.
+#
+# Authors: Andrew Beekhof
+# Steven Dake (sdake@redhat.com)
+#
+# This software licensed under BSD license, the text of which follows:
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# - Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# - Neither the name of the MontaVista Software, Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = lib
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/depcomp $(noinst_HEADERS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/lib/libcfg.verso $(top_srcdir)/lib/libcpg.verso \
+ $(top_srcdir)/lib/libquorum.verso \
+ $(top_srcdir)/lib/libsam.verso \
+ $(top_srcdir)/lib/libvotequorum.verso \
+ $(top_srcdir)/lib/libcmap.verso $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/include/corosync/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libcfg_la_LIBADD =
+am_libcfg_la_OBJECTS = cfg.lo
+libcfg_la_OBJECTS = $(am_libcfg_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libcmap_la_LIBADD =
+am_libcmap_la_OBJECTS = cmap.lo
+libcmap_la_OBJECTS = $(am_libcmap_la_OBJECTS)
+libcpg_la_LIBADD =
+am_libcpg_la_OBJECTS = cpg.lo
+libcpg_la_OBJECTS = $(am_libcpg_la_OBJECTS)
+libquorum_la_LIBADD =
+am_libquorum_la_OBJECTS = quorum.lo
+libquorum_la_OBJECTS = $(am_libquorum_la_OBJECTS)
+libsam_la_DEPENDENCIES = libquorum.la libcmap.la
+am_libsam_la_OBJECTS = sam.lo
+libsam_la_OBJECTS = $(am_libsam_la_OBJECTS)
+libvotequorum_la_LIBADD =
+am_libvotequorum_la_OBJECTS = votequorum.lo
+libvotequorum_la_OBJECTS = $(am_libvotequorum_la_OBJECTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/corosync
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libcfg_la_SOURCES) $(libcmap_la_SOURCES) \
+ $(libcpg_la_SOURCES) $(libquorum_la_SOURCES) \
+ $(libsam_la_SOURCES) $(libvotequorum_la_SOURCES)
+DIST_SOURCES = $(libcfg_la_SOURCES) $(libcmap_la_SOURCES) \
+ $(libcpg_la_SOURCES) $(libquorum_la_SOURCES) \
+ $(libsam_la_SOURCES) $(libvotequorum_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(noinst_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUGTOOL = @AUGTOOL@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BASHPATH = @BASHPATH@
+BINDGEN = @BINDGEN@
+CARGO = @CARGO@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFG_SONAME = @CFG_SONAME@
+CFLAGS = @CFLAGS@
+CLIPPY = @CLIPPY@
+CMAP_SONAME = @CMAP_SONAME@
+COROSYSCONFDIR = @COROSYSCONFDIR@
+CPG_SONAME = @CPG_SONAME@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_LIBS = @DBUS_LIBS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DOT = @DOT@
+DOXYGEN = @DOXYGEN@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+GROFF = @GROFF@
+INITCONFIGDIR = @INITCONFIGDIR@
+INITDDIR = @INITDDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBQB_CFLAGS = @LIBQB_CFLAGS@
+LIBQB_LIBS = @LIBQB_LIBS@
+
+# override global LIBS that pulls in lots of craft we don't need here
+LIBS = -version-number $(call get_soname,$<) \
+ @VERSCRIPT_LDFLAGS@ \
+ -lpthread \
+ $(top_builddir)/common_lib/libcorosync_common.la \
+ $(LIBQB_LIBS)
+
+LIBTOOL = @LIBTOOL@
+LINT_FLAGS = @LINT_FLAGS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LOGDIR = @LOGDIR@
+LOGROTATEDIR = @LOGROTATEDIR@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+QUORUM_SONAME = @QUORUM_SONAME@
+RANLIB = @RANLIB@
+RUSTC = @RUSTC@
+RUSTDOC = @RUSTDOC@
+RUSTFMT = @RUSTFMT@
+RUST_FLAGS = @RUST_FLAGS@
+RUST_TARGET_DIR = @RUST_TARGET_DIR@
+SAM_SONAME = @SAM_SONAME@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SNMPCONFIG = @SNMPCONFIG@
+SNMP_LIBS = @SNMP_LIBS@
+SOMAJOR = @SOMAJOR@
+SOMICRO = @SOMICRO@
+SOMINOR = @SOMINOR@
+SONAME = @SONAME@
+STRIP = @STRIP@
+SYSTEMDDIR = @SYSTEMDDIR@
+VERSCRIPT_LDFLAGS = @VERSCRIPT_LDFLAGS@
+VERSION = @VERSION@
+VOTEQUORUM_SONAME = @VOTEQUORUM_SONAME@
+WITH_LIST = @WITH_LIST@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+corosyncrustver = @corosyncrustver@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+knet_CFLAGS = @knet_CFLAGS@
+knet_LIBS = @knet_LIBS@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libsystemd_CFLAGS = @libsystemd_CFLAGS@
+libsystemd_LIBS = @libsystemd_LIBS@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+nozzle_CFLAGS = @nozzle_CFLAGS@
+nozzle_LIBS = @nozzle_LIBS@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+statgrab_CFLAGS = @statgrab_CFLAGS@
+statgrab_LIBS = @statgrab_LIBS@
+statgrabge090_CFLAGS = @statgrabge090_CFLAGS@
+statgrabge090_LIBS = @statgrabge090_LIBS@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+
+# Functions to be used at link time (target.lo)
+get_libname = $(shell echo $1 | $(SED) -e "s/\.lo//")
+uc = $(shell echo $(call get_libname,$1) | tr a-z A-Z)
+get_soname = $(subst .,:,$(if $($(call uc,$1)_SONAME),$($(call uc,$1)_SONAME),$(SONAME)))
+get_major = $(firstword $(subst :, ,$(call get_soname,$1)))
+MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = libcfg.versions libcfg.verso \
+ libcmap.versions libcmap.verso \
+ libcpg.versions libcpg.verso \
+ libquorum.versions libquorum.verso \
+ libsam.versions libsam.verso \
+ libvotequorum.versions libvotequorum.verso
+
+noinst_HEADERS = util.h
+lib_LTLIBRARIES = libcpg.la libquorum.la libcfg.la \
+ libvotequorum.la libcmap.la libsam.la
+
+libcpg_la_SOURCES = cpg.c
+libcfg_la_SOURCES = cfg.c
+libquorum_la_SOURCES = quorum.c
+libvotequorum_la_SOURCES = votequorum.c
+libcmap_la_SOURCES = cmap.c
+libsam_la_SOURCES = sam.c
+libsam_la_LIBADD = libquorum.la libcmap.la
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign lib/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libcfg.la: $(libcfg_la_OBJECTS) $(libcfg_la_DEPENDENCIES) $(EXTRA_libcfg_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcfg_la_OBJECTS) $(libcfg_la_LIBADD) $(LIBS)
+
+libcmap.la: $(libcmap_la_OBJECTS) $(libcmap_la_DEPENDENCIES) $(EXTRA_libcmap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcmap_la_OBJECTS) $(libcmap_la_LIBADD) $(LIBS)
+
+libcpg.la: $(libcpg_la_OBJECTS) $(libcpg_la_DEPENDENCIES) $(EXTRA_libcpg_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libcpg_la_OBJECTS) $(libcpg_la_LIBADD) $(LIBS)
+
+libquorum.la: $(libquorum_la_OBJECTS) $(libquorum_la_DEPENDENCIES) $(EXTRA_libquorum_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libquorum_la_OBJECTS) $(libquorum_la_LIBADD) $(LIBS)
+
+libsam.la: $(libsam_la_OBJECTS) $(libsam_la_DEPENDENCIES) $(EXTRA_libsam_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libsam_la_OBJECTS) $(libsam_la_LIBADD) $(LIBS)
+
+libvotequorum.la: $(libvotequorum_la_OBJECTS) $(libvotequorum_la_DEPENDENCIES) $(EXTRA_libvotequorum_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libvotequorum_la_OBJECTS) $(libvotequorum_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cfg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cmap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cpg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quorum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sam.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/votequorum.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/lib/cfg.c b/lib/cfg.c
new file mode 100644
index 0000000..f0a3e9a
--- /dev/null
+++ b/lib/cfg.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (c) 2002-2005 MontaVista Software, Inc.
+ * Copyright (c) 2006-2020 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/un.h>
+#include <sys/uio.h>
+
+#include <qb/qbipcc.h>
+
+#include <corosync/corotypes.h>
+#include <corosync/corodefs.h>
+#include <corosync/hdb.h>
+
+#include <corosync/cfg.h>
+#include <corosync/ipc_cfg.h>
+
+#include "util.h"
+
+/*
+ * Data structure for instance data
+ */
+struct cfg_inst {
+ qb_ipcc_connection_t *c;
+ corosync_cfg_callbacks_t callbacks;
+ cs_name_t comp_name;
+ int comp_registered;
+ int finalize;
+};
+
+/*
+ * All instances in one database
+ */
+static void cfg_inst_free (void *inst);
+
+DECLARE_HDB_DATABASE (cfg_hdb, cfg_inst_free);
+
+/*
+ * Implementation
+ */
+
+cs_error_t
+corosync_cfg_initialize (
+ corosync_cfg_handle_t *cfg_handle,
+ const corosync_cfg_callbacks_t *cfg_callbacks)
+{
+ struct cfg_inst *cfg_inst;
+ cs_error_t error = CS_OK;
+
+ error = hdb_error_to_cs (hdb_handle_create (&cfg_hdb, sizeof (struct cfg_inst), cfg_handle));
+ if (error != CS_OK) {
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, *cfg_handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ cfg_inst->finalize = 0;
+ cfg_inst->c = qb_ipcc_connect ("cfg", IPC_REQUEST_SIZE);
+ if (cfg_inst->c == NULL) {
+ error = qb_to_cs_error(-errno);
+ goto error_put_destroy;
+ }
+
+ if (cfg_callbacks) {
+ memcpy (&cfg_inst->callbacks, cfg_callbacks, sizeof (corosync_cfg_callbacks_t));
+ }
+
+ (void)hdb_handle_put (&cfg_hdb, *cfg_handle);
+
+ return (CS_OK);
+
+error_put_destroy:
+ (void)hdb_handle_put (&cfg_hdb, *cfg_handle);
+error_destroy:
+ (void)hdb_handle_destroy (&cfg_hdb, *cfg_handle);
+error_no_destroy:
+ return (error);
+}
+
+cs_error_t
+corosync_cfg_fd_get (
+ corosync_cfg_handle_t cfg_handle,
+ int32_t *selection_fd)
+{
+ struct cfg_inst *cfg_inst;
+ cs_error_t error;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = qb_to_cs_error (qb_ipcc_fd_get (cfg_inst->c, selection_fd));
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+ return (error);
+}
+
+cs_error_t
+corosync_cfg_dispatch (
+ corosync_cfg_handle_t cfg_handle,
+ cs_dispatch_flags_t dispatch_flags)
+{
+ int timeout = -1;
+ cs_error_t error;
+ int cont = 1; /* always continue do loop except when set to 0 */
+ struct cfg_inst *cfg_inst;
+ struct res_lib_cfg_testshutdown *res_lib_cfg_testshutdown;
+ corosync_cfg_callbacks_t callbacks;
+ struct qb_ipc_response_header *dispatch_data;
+ char dispatch_buf[IPC_DISPATCH_SIZE];
+
+ error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
+ * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
+ */
+ if (dispatch_flags == CS_DISPATCH_ALL || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) {
+ timeout = 0;
+ }
+
+ dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
+ do {
+ error = qb_to_cs_error (qb_ipcc_event_recv (
+ cfg_inst->c,
+ dispatch_buf,
+ IPC_DISPATCH_SIZE,
+ timeout));
+ if (error == CS_ERR_BAD_HANDLE) {
+ error = CS_OK;
+ goto error_put;
+ }
+ if (error == CS_ERR_TRY_AGAIN) {
+ if (dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) {
+ /*
+ * Don't mask error
+ */
+ goto error_put;
+ }
+ error = CS_OK;
+ if (dispatch_flags == CS_DISPATCH_ALL) {
+ break; /* exit do while cont is 1 loop */
+ } else {
+ continue; /* next poll */
+ }
+ }
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ /*
+ * Make copy of callbacks, message data, unlock instance, and call callback
+ * A risk of this dispatch method is that the callback routines may
+ * operate at the same time that cfgFinalize has been called in another thread.
+ */
+ memcpy (&callbacks, &cfg_inst->callbacks, sizeof (corosync_cfg_callbacks_t));
+
+ /*
+ * Dispatch incoming response
+ */
+ switch (dispatch_data->id) {
+ case MESSAGE_RES_CFG_TESTSHUTDOWN:
+ if (callbacks.corosync_cfg_shutdown_callback == NULL) {
+ break;
+ }
+
+ res_lib_cfg_testshutdown = (struct res_lib_cfg_testshutdown *)dispatch_data;
+ callbacks.corosync_cfg_shutdown_callback(cfg_handle, res_lib_cfg_testshutdown->flags);
+ break;
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_nounlock;
+ break;
+ }
+ if (cfg_inst->finalize) {
+ /*
+ * If the finalize has been called then get out of the dispatch.
+ */
+ error = CS_ERR_BAD_HANDLE;
+ goto error_put;
+ }
+
+ /*
+ * Determine if more messages should be processed
+ */
+ if (dispatch_flags == CS_DISPATCH_ONE || dispatch_flags == CS_DISPATCH_ONE_NONBLOCKING) {
+ cont = 0;
+ }
+ } while (cont);
+
+error_put:
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+error_nounlock:
+ return (error);
+}
+
+static void cfg_inst_free (void *inst)
+{
+ struct cfg_inst *cfg_inst = (struct cfg_inst *)inst;
+ qb_ipcc_disconnect(cfg_inst->c);
+}
+
+cs_error_t
+corosync_cfg_finalize (
+ corosync_cfg_handle_t cfg_handle)
+{
+ struct cfg_inst *cfg_inst;
+ cs_error_t error;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Another thread has already started finalizing
+ */
+ if (cfg_inst->finalize) {
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ cfg_inst->finalize = 1;
+
+ (void)hdb_handle_destroy (&cfg_hdb, cfg_handle);
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error);
+}
+
+cs_error_t
+corosync_cfg_ring_status_get (
+ corosync_cfg_handle_t cfg_handle,
+ char ***interface_names,
+ char ***status,
+ unsigned int *interface_count)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_ringstatusget req_lib_cfg_ringstatusget;
+ struct res_lib_cfg_ringstatusget res_lib_cfg_ringstatusget;
+ unsigned int i, j;
+ cs_error_t error;
+ struct iovec iov;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_ringstatusget.header.size = sizeof (struct req_lib_cfg_ringstatusget);
+ req_lib_cfg_ringstatusget.header.id = MESSAGE_REQ_CFG_RINGSTATUSGET;
+
+ iov.iov_base = (void *)&req_lib_cfg_ringstatusget,
+ iov.iov_len = sizeof (struct req_lib_cfg_ringstatusget),
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv(cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_ringstatusget,
+ sizeof (struct res_lib_cfg_ringstatusget), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto exit_handle_put;
+ }
+
+ *interface_count = res_lib_cfg_ringstatusget.interface_count;
+ *interface_names = malloc (sizeof (char *) * *interface_count);
+ if (*interface_names == NULL) {
+ return (CS_ERR_NO_MEMORY);
+ }
+ memset (*interface_names, 0, sizeof (char *) * *interface_count);
+
+ *status = malloc (sizeof (char *) * *interface_count);
+ if (*status == NULL) {
+ error = CS_ERR_NO_MEMORY;
+ goto error_free_interface_names_array;
+ }
+ memset (*status, 0, sizeof (char *) * *interface_count);
+
+ for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) {
+ (*(interface_names))[i] = strdup (res_lib_cfg_ringstatusget.interface_name[i]);
+ if ((*(interface_names))[i] == NULL) {
+ error = CS_ERR_NO_MEMORY;
+ goto error_free_interface_names;
+ }
+ }
+
+ for (i = 0; i < res_lib_cfg_ringstatusget.interface_count; i++) {
+ (*(status))[i] = strdup (res_lib_cfg_ringstatusget.interface_status[i]);
+ if ((*(status))[i] == NULL) {
+ error = CS_ERR_NO_MEMORY;
+ goto error_free_status;
+ }
+ }
+ goto exit_handle_put;
+
+error_free_status:
+ for (j = 0; j < i; j++) {
+ free ((*(status))[j]);
+ }
+ i = *interface_count;
+
+error_free_interface_names:
+ for (j = 0; j < i; j++) {
+ free ((*(interface_names))[j]);
+ }
+
+ free (*status);
+
+error_free_interface_names_array:
+ free (*interface_names);
+
+exit_handle_put:
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error);
+}
+
+cs_error_t
+corosync_cfg_node_status_get (
+ corosync_cfg_handle_t cfg_handle,
+ unsigned int nodeid,
+ corosync_cfg_node_status_version_t version,
+ void *node_status)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_nodestatusget req_lib_cfg_nodestatusget;
+ cs_error_t error;
+ struct iovec iov;
+ size_t cfg_node_status_size;
+ void *res_lib_cfg_nodestatuget_ptr;
+ struct res_lib_cfg_nodestatusget_v1 res_lib_cfg_nodestatusget_v1;
+ struct res_lib_cfg_nodestatusget_version *res_lib_cfg_nodestatusget_version;
+
+ if (!node_status) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ switch (version) {
+ case CFG_NODE_STATUS_V1:
+ cfg_node_status_size = sizeof(struct res_lib_cfg_nodestatusget_v1);
+ res_lib_cfg_nodestatuget_ptr = &res_lib_cfg_nodestatusget_v1;
+
+ break;
+ default:
+ return (CS_ERR_INVALID_PARAM);
+ break;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_nodestatusget.header.size = sizeof (struct req_lib_cfg_nodestatusget);
+ req_lib_cfg_nodestatusget.header.id = MESSAGE_REQ_CFG_NODESTATUSGET;
+ req_lib_cfg_nodestatusget.nodeid = nodeid;
+ req_lib_cfg_nodestatusget.version = version;
+
+ iov.iov_base = (void *)&req_lib_cfg_nodestatusget,
+ iov.iov_len = sizeof (struct req_lib_cfg_nodestatusget),
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv(cfg_inst->c,
+ &iov,
+ 1,
+ res_lib_cfg_nodestatuget_ptr,
+ cfg_node_status_size, CS_IPC_TIMEOUT_MS));
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ res_lib_cfg_nodestatusget_version = res_lib_cfg_nodestatuget_ptr;
+ error = res_lib_cfg_nodestatusget_version->header.error;
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ if (res_lib_cfg_nodestatusget_version->version != version) {
+ /*
+ * corosync sent us something we don't really understand.
+ */
+ error = CS_ERR_NOT_SUPPORTED;
+ goto error_put;
+ }
+
+ switch (version) {
+ case CFG_NODE_STATUS_V1:
+ memcpy(node_status, &res_lib_cfg_nodestatusget_v1.node_status,
+ sizeof(struct corosync_cfg_node_status_v1));
+ break;
+ }
+
+error_put:
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error);
+}
+
+
+cs_error_t
+corosync_cfg_trackstart (
+ corosync_cfg_handle_t cfg_handle,
+ uint8_t track_flags)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_trackstart req_lib_cfg_trackstart;
+ struct res_lib_cfg_trackstart res_lib_cfg_trackstart;
+ cs_error_t error;
+ struct iovec iov;
+
+ req_lib_cfg_trackstart.header.size = sizeof (struct req_lib_cfg_trackstart);
+ req_lib_cfg_trackstart.header.id = MESSAGE_REQ_CFG_TRACKSTART;
+ req_lib_cfg_trackstart.track_flags = track_flags;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ iov.iov_base = (void *)&req_lib_cfg_trackstart,
+ iov.iov_len = sizeof (struct req_lib_cfg_trackstart),
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_trackstart,
+ sizeof (struct res_lib_cfg_trackstart), CS_IPC_TIMEOUT_MS));
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error == CS_OK ? res_lib_cfg_trackstart.header.error : error);
+}
+
+cs_error_t
+corosync_cfg_trackstop (
+ corosync_cfg_handle_t cfg_handle)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_trackstop req_lib_cfg_trackstop;
+ struct res_lib_cfg_trackstop res_lib_cfg_trackstop;
+ cs_error_t error;
+ struct iovec iov;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_trackstop.header.size = sizeof (struct req_lib_cfg_trackstop);
+ req_lib_cfg_trackstop.header.id = MESSAGE_REQ_CFG_TRACKSTOP;
+
+ iov.iov_base = (void *)&req_lib_cfg_trackstop,
+ iov.iov_len = sizeof (struct req_lib_cfg_trackstop),
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_trackstop,
+ sizeof (struct res_lib_cfg_trackstop), CS_IPC_TIMEOUT_MS));
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error == CS_OK ? res_lib_cfg_trackstop.header.error : error);
+}
+
+cs_error_t
+corosync_cfg_kill_node (
+ corosync_cfg_handle_t cfg_handle,
+ unsigned int nodeid,
+ const char *reason)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_killnode req_lib_cfg_killnode;
+ struct res_lib_cfg_killnode res_lib_cfg_killnode;
+ cs_error_t error;
+ struct iovec iov;
+
+ if (strlen(reason) >= CS_MAX_NAME_LENGTH)
+ return CS_ERR_NAME_TOO_LONG;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_killnode.header.id = MESSAGE_REQ_CFG_KILLNODE;
+ req_lib_cfg_killnode.header.size = sizeof (struct req_lib_cfg_killnode);
+ req_lib_cfg_killnode.nodeid = nodeid;
+ strcpy((char *)req_lib_cfg_killnode.reason.value, reason);
+ req_lib_cfg_killnode.reason.length = strlen(reason)+1;
+
+ iov.iov_base = (void *)&req_lib_cfg_killnode;
+ iov.iov_len = sizeof (struct req_lib_cfg_killnode);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_killnode,
+ sizeof (struct res_lib_cfg_killnode), CS_IPC_TIMEOUT_MS));
+
+ error = res_lib_cfg_killnode.header.error;
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error == CS_OK ? res_lib_cfg_killnode.header.error : error);
+}
+
+cs_error_t
+corosync_cfg_try_shutdown (
+ corosync_cfg_handle_t cfg_handle,
+ corosync_cfg_shutdown_flags_t flags)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_tryshutdown req_lib_cfg_tryshutdown;
+ struct res_lib_cfg_tryshutdown res_lib_cfg_tryshutdown;
+ cs_error_t error;
+ struct iovec iov;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_tryshutdown.header.id = MESSAGE_REQ_CFG_TRYSHUTDOWN;
+ req_lib_cfg_tryshutdown.header.size = sizeof (struct req_lib_cfg_tryshutdown);
+ req_lib_cfg_tryshutdown.flags = flags;
+
+ iov.iov_base = (void *)&req_lib_cfg_tryshutdown;
+ iov.iov_len = sizeof (req_lib_cfg_tryshutdown);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_tryshutdown,
+ sizeof (struct res_lib_cfg_tryshutdown), CS_IPC_TIMEOUT_MS));
+
+ (void)hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error == CS_OK ? res_lib_cfg_tryshutdown.header.error : error);
+}
+
+cs_error_t
+corosync_cfg_replyto_shutdown (
+ corosync_cfg_handle_t cfg_handle,
+ corosync_cfg_shutdown_reply_flags_t response)
+{
+ struct cfg_inst *cfg_inst;
+ struct req_lib_cfg_replytoshutdown req_lib_cfg_replytoshutdown;
+ struct res_lib_cfg_replytoshutdown res_lib_cfg_replytoshutdown;
+ struct iovec iov;
+ cs_error_t error;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_replytoshutdown.header.id = MESSAGE_REQ_CFG_REPLYTOSHUTDOWN;
+ req_lib_cfg_replytoshutdown.header.size = sizeof (struct req_lib_cfg_replytoshutdown);
+ req_lib_cfg_replytoshutdown.response = response;
+
+ iov.iov_base = (void *)&req_lib_cfg_replytoshutdown;
+ iov.iov_len = sizeof (struct req_lib_cfg_replytoshutdown);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_replytoshutdown,
+ sizeof (struct res_lib_cfg_replytoshutdown), CS_IPC_TIMEOUT_MS));
+
+ return (error);
+}
+
+cs_error_t corosync_cfg_get_node_addrs (
+ corosync_cfg_handle_t cfg_handle,
+ unsigned int nodeid,
+ size_t max_addrs,
+ int *num_addrs,
+ corosync_cfg_node_address_t *addrs)
+{
+ cs_error_t error;
+ struct req_lib_cfg_get_node_addrs req_lib_cfg_get_node_addrs;
+ struct res_lib_cfg_get_node_addrs *res_lib_cfg_get_node_addrs;
+ struct cfg_inst *cfg_inst;
+ int addrlen = 0;
+ int i;
+ struct iovec iov;
+ const char *addr_buf;
+ char response_buf[IPC_RESPONSE_SIZE];
+ char zeroes[sizeof(struct sockaddr_storage)];
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, cfg_handle,
+ (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+ memset(zeroes, 0, sizeof(zeroes));
+
+ req_lib_cfg_get_node_addrs.header.size = sizeof (req_lib_cfg_get_node_addrs);
+ req_lib_cfg_get_node_addrs.header.id = MESSAGE_REQ_CFG_GET_NODE_ADDRS;
+ req_lib_cfg_get_node_addrs.nodeid = nodeid;
+
+ iov.iov_base = (char *)&req_lib_cfg_get_node_addrs;
+ iov.iov_len = sizeof (req_lib_cfg_get_node_addrs);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (
+ cfg_inst->c,
+ &iov, 1,
+ response_buf, IPC_RESPONSE_SIZE, CS_IPC_TIMEOUT_MS));
+ res_lib_cfg_get_node_addrs = (struct res_lib_cfg_get_node_addrs *)response_buf;
+
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ if (res_lib_cfg_get_node_addrs->family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ if (res_lib_cfg_get_node_addrs->family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+
+ for (i = 0, addr_buf = (char *)res_lib_cfg_get_node_addrs->addrs;
+ i < max_addrs && i<res_lib_cfg_get_node_addrs->num_addrs;
+ i++, addr_buf += TOTEMIP_ADDRLEN) {
+ struct sockaddr_in *in;
+ struct sockaddr_in6 *in6;
+
+ addrs[i].address_length = addrlen;
+
+ if (res_lib_cfg_get_node_addrs->family == AF_INET) {
+ in = (struct sockaddr_in *)addrs[i].address;
+ if (memcmp(addr_buf, zeroes, addrlen) == 0) {
+ in->sin_family = 0;
+ } else {
+ in->sin_family = AF_INET;
+ }
+ memcpy(&in->sin_addr, addr_buf, sizeof(struct in_addr));
+ }
+ if (res_lib_cfg_get_node_addrs->family == AF_INET6) {
+ in6 = (struct sockaddr_in6 *)addrs[i].address;
+
+ if (memcmp(addr_buf, zeroes, addrlen) == 0) {
+ in6->sin6_family = 0;
+ } else {
+ in6->sin6_family = AF_INET6;
+ }
+ memcpy(&in6->sin6_addr, addr_buf, sizeof(struct in6_addr));
+ }
+
+ /* Mark it as unused */
+
+ }
+ *num_addrs = res_lib_cfg_get_node_addrs->num_addrs;
+ errno = error = res_lib_cfg_get_node_addrs->header.error;
+
+error_put:
+ hdb_handle_put (&cfg_hdb, cfg_handle);
+
+ return (error);
+}
+
+cs_error_t corosync_cfg_local_get (
+ corosync_cfg_handle_t handle,
+ unsigned int *local_nodeid)
+{
+ cs_error_t error;
+ struct cfg_inst *cfg_inst;
+ struct iovec iov;
+ struct req_lib_cfg_local_get req_lib_cfg_local_get;
+ struct res_lib_cfg_local_get res_lib_cfg_local_get;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_local_get.header.size = sizeof (struct qb_ipc_request_header);
+ req_lib_cfg_local_get.header.id = MESSAGE_REQ_CFG_LOCAL_GET;
+
+ iov.iov_base = (void *)&req_lib_cfg_local_get;
+ iov.iov_len = sizeof (struct req_lib_cfg_local_get);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (
+ cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_local_get,
+ sizeof (struct res_lib_cfg_local_get), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cfg_local_get.header.error;
+
+ *local_nodeid = res_lib_cfg_local_get.local_nodeid;
+
+error_exit:
+ (void)hdb_handle_put (&cfg_hdb, handle);
+
+ return (error);
+}
+
+cs_error_t corosync_cfg_reload_config (
+ corosync_cfg_handle_t handle)
+{
+ cs_error_t error;
+ struct cfg_inst *cfg_inst;
+ struct iovec iov;
+ struct req_lib_cfg_reload_config req_lib_cfg_reload_config;
+ struct res_lib_cfg_reload_config res_lib_cfg_reload_config;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_reload_config.header.size = sizeof (struct qb_ipc_request_header);
+ req_lib_cfg_reload_config.header.id = MESSAGE_REQ_CFG_RELOAD_CONFIG;
+
+ iov.iov_base = (void *)&req_lib_cfg_reload_config;
+ iov.iov_len = sizeof (struct req_lib_cfg_reload_config);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (
+ cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_reload_config,
+ sizeof (struct res_lib_cfg_reload_config), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cfg_reload_config.header.error;
+
+error_exit:
+ (void)hdb_handle_put (&cfg_hdb, handle);
+
+ return (error);
+}
+
+cs_error_t corosync_cfg_reopen_log_files (
+ corosync_cfg_handle_t handle)
+{
+ cs_error_t error;
+ struct cfg_inst *cfg_inst;
+ struct iovec iov;
+ struct req_lib_cfg_reopen_log_files req_lib_cfg_reopen_log_files;
+ struct res_lib_cfg_reopen_log_files res_lib_cfg_reopen_log_files;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cfg_hdb, handle, (void *)&cfg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cfg_reopen_log_files.header.size = sizeof (struct qb_ipc_request_header);
+ req_lib_cfg_reopen_log_files.header.id = MESSAGE_REQ_CFG_REOPEN_LOG_FILES;
+
+ iov.iov_base = (void *)&req_lib_cfg_reopen_log_files;
+ iov.iov_len = sizeof (struct req_lib_cfg_reopen_log_files);
+
+ error = qb_to_cs_error (qb_ipcc_sendv_recv (
+ cfg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cfg_reopen_log_files,
+ sizeof (struct res_lib_cfg_reopen_log_files), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cfg_reopen_log_files.header.error;
+
+error_exit:
+ (void)hdb_handle_put (&cfg_hdb, handle);
+
+ return (error);
+}
diff --git a/lib/cmap.c b/lib/cmap.c
new file mode 100644
index 0000000..ed9774a
--- /dev/null
+++ b/lib/cmap.c
@@ -0,0 +1,1119 @@
+/*
+ * Copyright (c) 2011-2017 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the Red Hat, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <corosync/corotypes.h>
+#include <corosync/corodefs.h>
+#include <corosync/hdb.h>
+#include <qb/qbipcc.h>
+
+#include <corosync/cmap.h>
+#include <corosync/ipc_cmap.h>
+
+#include "util.h"
+#include <stdio.h>
+
+struct cmap_inst {
+ int finalize;
+ qb_ipcc_connection_t *c;
+ const void *context;
+};
+
+struct cmap_track_inst {
+ void *user_data;
+ cmap_notify_fn_t notify_fn;
+ qb_ipcc_connection_t *c;
+ cmap_track_handle_t track_handle;
+};
+
+static void cmap_inst_free (void *inst);
+
+DECLARE_HDB_DATABASE(cmap_handle_t_db, cmap_inst_free);
+DECLARE_HDB_DATABASE(cmap_track_handle_t_db,NULL);
+
+/*
+ * Function prototypes
+ */
+static cs_error_t cmap_get_int(
+ cmap_handle_t handle,
+ const char *key_name,
+ void *value,
+ size_t value_size,
+ cmap_value_types_t type);
+
+static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step);
+
+/*
+ * Function implementations
+ */
+cs_error_t cmap_initialize (cmap_handle_t *handle)
+{
+ cs_error_t error;
+ struct cmap_inst *cmap_inst;
+
+ error = hdb_error_to_cs(hdb_handle_create(&cmap_handle_t_db, sizeof(*cmap_inst), handle));
+ if (error != CS_OK) {
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, *handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ error = CS_OK;
+ cmap_inst->finalize = 0;
+ cmap_inst->c = qb_ipcc_connect("cmap", IPC_REQUEST_SIZE);
+ if (cmap_inst->c == NULL) {
+ error = qb_to_cs_error(-errno);
+ goto error_put_destroy;
+ }
+
+ (void)hdb_handle_put(&cmap_handle_t_db, *handle);
+
+ return (CS_OK);
+
+error_put_destroy:
+ (void)hdb_handle_put(&cmap_handle_t_db, *handle);
+error_destroy:
+ (void)hdb_handle_destroy(&cmap_handle_t_db, *handle);
+error_no_destroy:
+ return (error);
+}
+
+cs_error_t cmap_initialize_map (cmap_handle_t *handle,
+ cmap_map_t map)
+{
+ cs_error_t error;
+ struct iovec iov[1];
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_set_current_map req_lib_cmap_set_current_map;
+ struct qb_ipc_response_header res_lib_cmap_set_current_map;
+
+ error = cmap_initialize(handle);
+
+ if (error == CS_OK) {
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, *handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_set_current_map, 0, sizeof(req_lib_cmap_set_current_map));
+ req_lib_cmap_set_current_map.header.size = sizeof(req_lib_cmap_set_current_map);
+ req_lib_cmap_set_current_map.header.id = MESSAGE_REQ_CMAP_SET_CURRENT_MAP;
+ req_lib_cmap_set_current_map.map = map;
+
+ iov[0].iov_base = (char *)&req_lib_cmap_set_current_map;
+ iov[0].iov_len = sizeof(req_lib_cmap_set_current_map);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ iov,
+ 1,
+ &res_lib_cmap_set_current_map,
+ sizeof (res_lib_cmap_set_current_map), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_set_current_map.error;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, *handle);
+
+ return (error);
+ }
+ return (error);
+}
+
+static void cmap_inst_free (void *inst)
+{
+ struct cmap_inst *cmap_inst = (struct cmap_inst *)inst;
+ qb_ipcc_disconnect(cmap_inst->c);
+}
+
+cs_error_t cmap_finalize(cmap_handle_t handle)
+{
+ struct cmap_inst *cmap_inst;
+ cs_error_t error;
+ hdb_handle_t track_inst_handle = 0;
+ struct cmap_track_inst *cmap_track_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ if (cmap_inst->finalize) {
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+ return (CS_ERR_BAD_HANDLE);
+ }
+ cmap_inst->finalize = 1;
+
+ /*
+ * Destroy all track instances for given connection
+ */
+ hdb_iterator_reset(&cmap_track_handle_t_db);
+ while (hdb_iterator_next(&cmap_track_handle_t_db,
+ (void*)&cmap_track_inst, &track_inst_handle) == 0) {
+
+ if (cmap_track_inst->c == cmap_inst->c) {
+ (void)hdb_handle_destroy(&cmap_track_handle_t_db, track_inst_handle);
+ }
+
+ (void)hdb_handle_put (&cmap_track_handle_t_db, track_inst_handle);
+ }
+
+ (void)hdb_handle_destroy(&cmap_handle_t_db, handle);
+
+ (void)hdb_handle_put(&cmap_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t cmap_fd_get(cmap_handle_t handle, int *fd)
+{
+ cs_error_t error;
+ struct cmap_inst *cmap_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = qb_to_cs_error (qb_ipcc_fd_get (cmap_inst->c, fd));
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_dispatch (
+ cmap_handle_t handle,
+ cs_dispatch_flags_t dispatch_types)
+{
+ int timeout = -1;
+ cs_error_t error;
+ int cont = 1; /* always continue do loop except when set to 0 */
+ struct cmap_inst *cmap_inst;
+ struct qb_ipc_response_header *dispatch_data;
+ char dispatch_buf[IPC_DISPATCH_SIZE];
+ struct res_lib_cmap_notify_callback *res_lib_cmap_notify_callback;
+ struct cmap_track_inst *cmap_track_inst;
+ struct cmap_notify_value old_val;
+ struct cmap_notify_value new_val;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
+ * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
+ */
+ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ timeout = 0;
+ }
+
+ dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
+ do {
+ error = qb_to_cs_error(qb_ipcc_event_recv (
+ cmap_inst->c,
+ dispatch_buf,
+ IPC_DISPATCH_SIZE,
+ timeout));
+
+ if (error == CS_ERR_BAD_HANDLE) {
+ error = CS_OK;
+ goto error_put;
+ }
+ if (error == CS_ERR_TRY_AGAIN) {
+ if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ /*
+ * Don't mask error
+ */
+ goto error_put;
+ }
+ error = CS_OK;
+ if (dispatch_types == CS_DISPATCH_ALL) {
+ break; /* exit do while cont is 1 loop */
+ } else {
+ continue; /* next poll */
+ }
+ }
+
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ /*
+ * Dispatch incoming message
+ */
+ switch (dispatch_data->id) {
+ case MESSAGE_RES_CMAP_NOTIFY_CALLBACK:
+ res_lib_cmap_notify_callback = (struct res_lib_cmap_notify_callback *)dispatch_data;
+
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db,
+ res_lib_cmap_notify_callback->track_inst_handle,
+ (void *)&cmap_track_inst));
+ if (error == CS_ERR_BAD_HANDLE) {
+ /*
+ * User deleted tracker -> ignore error
+ */
+ break;
+ }
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ new_val.type = res_lib_cmap_notify_callback->new_value_type;
+ old_val.type = res_lib_cmap_notify_callback->old_value_type;
+ new_val.len = res_lib_cmap_notify_callback->new_value_len;
+ old_val.len = res_lib_cmap_notify_callback->old_value_len;
+ new_val.data = res_lib_cmap_notify_callback->new_value;
+ old_val.data = (((const char *)res_lib_cmap_notify_callback->new_value) + new_val.len);
+
+ cmap_track_inst->notify_fn(handle,
+ cmap_track_inst->track_handle,
+ res_lib_cmap_notify_callback->event,
+ (char *)res_lib_cmap_notify_callback->key_name.value,
+ new_val,
+ old_val,
+ cmap_track_inst->user_data);
+
+ (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_notify_callback->track_inst_handle);
+ break;
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_put;
+ break;
+ }
+ if (cmap_inst->finalize) {
+ /*
+ * If the finalize has been called then get out of the dispatch.
+ */
+ error = CS_ERR_BAD_HANDLE;
+ goto error_put;
+ }
+
+ /*
+ * Determine if more messages should be processed
+ */
+ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ cont = 0;
+ }
+ } while (cont);
+
+error_put:
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_context_get (
+ cmap_handle_t handle,
+ const void **context)
+{
+ cs_error_t error;
+ struct cmap_inst *cmap_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ *context = cmap_inst->context;
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t cmap_context_set (
+ cmap_handle_t handle,
+ const void *context)
+{
+ cs_error_t error;
+ struct cmap_inst *cmap_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ cmap_inst->context = context;
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t cmap_set (
+ cmap_handle_t handle,
+ const char *key_name,
+ const void *value,
+ size_t value_len,
+ cmap_value_types_t type)
+{
+ cs_error_t error;
+ struct iovec iov[2];
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_set req_lib_cmap_set;
+ struct res_lib_cmap_set res_lib_cmap_set;
+
+ if (key_name == NULL || value == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (strlen(key_name) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_set, 0, sizeof(req_lib_cmap_set));
+ req_lib_cmap_set.header.size = sizeof(req_lib_cmap_set) + value_len;
+ req_lib_cmap_set.header.id = MESSAGE_REQ_CMAP_SET;
+
+ memcpy(req_lib_cmap_set.key_name.value, key_name, strlen(key_name));
+ req_lib_cmap_set.key_name.length = strlen(key_name);
+
+ req_lib_cmap_set.value_len = value_len;
+ req_lib_cmap_set.type = type;
+
+ iov[0].iov_base = (char *)&req_lib_cmap_set;
+ iov[0].iov_len = sizeof(req_lib_cmap_set);
+ iov[1].iov_base = (void *)value;
+ iov[1].iov_len = value_len;
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ iov,
+ 2,
+ &res_lib_cmap_set,
+ sizeof (struct res_lib_cmap_set), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_set.header.error;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_set_int8(cmap_handle_t handle, const char *key_name, int8_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT8));
+}
+
+cs_error_t cmap_set_uint8(cmap_handle_t handle, const char *key_name, uint8_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT8));
+}
+
+cs_error_t cmap_set_int16(cmap_handle_t handle, const char *key_name, int16_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT16));
+}
+
+cs_error_t cmap_set_uint16(cmap_handle_t handle, const char *key_name, uint16_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT16));
+}
+
+cs_error_t cmap_set_int32(cmap_handle_t handle, const char *key_name, int32_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT32));
+}
+
+cs_error_t cmap_set_uint32(cmap_handle_t handle, const char *key_name, uint32_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT32));
+}
+
+cs_error_t cmap_set_int64(cmap_handle_t handle, const char *key_name, int64_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_INT64));
+}
+
+cs_error_t cmap_set_uint64(cmap_handle_t handle, const char *key_name, uint64_t value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_UINT64));
+}
+
+cs_error_t cmap_set_float(cmap_handle_t handle, const char *key_name, float value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_FLOAT));
+}
+
+cs_error_t cmap_set_double(cmap_handle_t handle, const char *key_name, double value)
+{
+ return (cmap_set(handle, key_name, &value, sizeof(value), CMAP_VALUETYPE_DOUBLE));
+}
+
+cs_error_t cmap_set_string(cmap_handle_t handle, const char *key_name, const char *value)
+{
+
+ if (value == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ return (cmap_set(handle, key_name, value, strlen(value), CMAP_VALUETYPE_STRING));
+}
+
+cs_error_t cmap_delete(cmap_handle_t handle, const char *key_name)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_delete req_lib_cmap_delete;
+ struct res_lib_cmap_delete res_lib_cmap_delete;
+
+ if (key_name == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+ if (strlen(key_name) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_delete, 0, sizeof(req_lib_cmap_delete));
+ req_lib_cmap_delete.header.size = sizeof(req_lib_cmap_delete);
+ req_lib_cmap_delete.header.id = MESSAGE_REQ_CMAP_DELETE;
+
+ memcpy(req_lib_cmap_delete.key_name.value, key_name, strlen(key_name));
+ req_lib_cmap_delete.key_name.length = strlen(key_name);
+
+ iov.iov_base = (char *)&req_lib_cmap_delete;
+ iov.iov_len = sizeof(req_lib_cmap_delete);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_delete,
+ sizeof (struct res_lib_cmap_delete), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_delete.header.error;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_get(
+ cmap_handle_t handle,
+ const char *key_name,
+ void *value,
+ size_t *value_len,
+ cmap_value_types_t *type)
+{
+ cs_error_t error;
+ struct cmap_inst *cmap_inst;
+ struct iovec iov;
+ struct req_lib_cmap_get req_lib_cmap_get;
+ struct res_lib_cmap_get *res_lib_cmap_get;
+ size_t res_size;
+
+ if (key_name == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+ if (strlen(key_name) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ if (value != NULL && value_len == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_get, 0, sizeof(req_lib_cmap_get));
+ req_lib_cmap_get.header.size = sizeof(req_lib_cmap_get);
+ req_lib_cmap_get.header.id = MESSAGE_REQ_CMAP_GET;
+
+ memcpy(req_lib_cmap_get.key_name.value, key_name, strlen(key_name));
+ req_lib_cmap_get.key_name.length = strlen(key_name);
+
+ if (value != NULL && value_len != NULL) {
+ req_lib_cmap_get.value_len = *value_len;
+ } else {
+ req_lib_cmap_get.value_len = 0;
+ }
+
+ iov.iov_base = (char *)&req_lib_cmap_get;
+ iov.iov_len = sizeof(req_lib_cmap_get);
+
+ res_size = sizeof(struct res_lib_cmap_get) + req_lib_cmap_get.value_len;
+
+ res_lib_cmap_get = malloc(res_size);
+ if (res_lib_cmap_get == NULL) {
+ return (CS_ERR_NO_MEMORY);
+ }
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ res_lib_cmap_get,
+ res_size, CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_get->header.error;
+ }
+
+ if (error == CS_OK) {
+ if (type != NULL) {
+ *type = res_lib_cmap_get->type;
+ }
+
+ if (value_len != NULL) {
+ *value_len = res_lib_cmap_get->value_len;
+ }
+
+ if (value != NULL && value_len != NULL) {
+ memcpy(value, res_lib_cmap_get->value, res_lib_cmap_get->value_len);
+ }
+ }
+
+ free(res_lib_cmap_get);
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+static cs_error_t cmap_get_int(
+ cmap_handle_t handle,
+ const char *key_name,
+ void *value,
+ size_t value_size,
+ cmap_value_types_t type)
+{
+ char key_value[16];
+ size_t key_size;
+ cs_error_t err;
+
+ cmap_value_types_t key_type;
+
+ key_size = sizeof(key_value);
+ memset(key_value, 0, key_size);
+
+ err = cmap_get(handle, key_name, key_value, &key_size, &key_type);
+ if (err != CS_OK)
+ return (err);
+
+ if (key_type != type) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ memcpy(value, key_value, value_size);
+
+ return (CS_OK);
+}
+
+cs_error_t cmap_get_int8(cmap_handle_t handle, const char *key_name, int8_t *i8)
+{
+
+ return (cmap_get_int(handle, key_name, i8, sizeof(*i8), CMAP_VALUETYPE_INT8));
+}
+
+cs_error_t cmap_get_uint8(cmap_handle_t handle, const char *key_name, uint8_t *u8)
+{
+
+ return (cmap_get_int(handle, key_name, u8, sizeof(*u8), CMAP_VALUETYPE_UINT8));
+}
+
+cs_error_t cmap_get_int16(cmap_handle_t handle, const char *key_name, int16_t *i16)
+{
+
+ return (cmap_get_int(handle, key_name, i16, sizeof(*i16), CMAP_VALUETYPE_INT16));
+}
+
+cs_error_t cmap_get_uint16(cmap_handle_t handle, const char *key_name, uint16_t *u16)
+{
+
+ return (cmap_get_int(handle, key_name, u16, sizeof(*u16), CMAP_VALUETYPE_UINT16));
+}
+
+cs_error_t cmap_get_int32(cmap_handle_t handle, const char *key_name, int32_t *i32)
+{
+
+ return (cmap_get_int(handle, key_name, i32, sizeof(*i32), CMAP_VALUETYPE_INT32));
+}
+
+cs_error_t cmap_get_uint32(cmap_handle_t handle, const char *key_name, uint32_t *u32)
+{
+
+ return (cmap_get_int(handle, key_name, u32, sizeof(*u32), CMAP_VALUETYPE_UINT32));
+}
+
+cs_error_t cmap_get_int64(cmap_handle_t handle, const char *key_name, int64_t *i64)
+{
+
+ return (cmap_get_int(handle, key_name, i64, sizeof(*i64), CMAP_VALUETYPE_INT64));
+}
+
+cs_error_t cmap_get_uint64(cmap_handle_t handle, const char *key_name, uint64_t *u64)
+{
+
+ return (cmap_get_int(handle, key_name, u64, sizeof(*u64), CMAP_VALUETYPE_UINT64));
+}
+
+cs_error_t cmap_get_float(cmap_handle_t handle, const char *key_name, float *flt)
+{
+
+ return (cmap_get_int(handle, key_name, flt, sizeof(*flt), CMAP_VALUETYPE_FLOAT));
+}
+
+cs_error_t cmap_get_double(cmap_handle_t handle, const char *key_name, double *dbl)
+{
+
+ return (cmap_get_int(handle, key_name, dbl, sizeof(*dbl), CMAP_VALUETYPE_DOUBLE));
+}
+
+cs_error_t cmap_get_string(cmap_handle_t handle, const char *key_name, char **str)
+{
+ cs_error_t res;
+ size_t str_len;
+ cmap_value_types_t type;
+
+ res = cmap_get(handle, key_name, NULL, &str_len, &type);
+
+ if (res != CS_OK || type != CMAP_VALUETYPE_STRING) {
+ if (res == CS_OK) {
+ res = CS_ERR_INVALID_PARAM;
+ }
+
+ goto return_error;
+ }
+
+ *str = malloc(str_len);
+ if (*str == NULL) {
+ res = CS_ERR_NO_MEMORY;
+
+ goto return_error;
+ }
+
+ res = cmap_get(handle, key_name, *str, &str_len, &type);
+ if (res != CS_OK) {
+ free(*str);
+
+ goto return_error;
+ }
+
+ return (CS_OK);
+
+return_error:
+ return (res);
+}
+
+static cs_error_t cmap_adjust_int(cmap_handle_t handle, const char *key_name, int32_t step)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_adjust_int req_lib_cmap_adjust_int;
+ struct res_lib_cmap_adjust_int res_lib_cmap_adjust_int;
+
+ if (key_name == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+ if (strlen(key_name) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_adjust_int, 0, sizeof(req_lib_cmap_adjust_int));
+ req_lib_cmap_adjust_int.header.size = sizeof(req_lib_cmap_adjust_int);
+ req_lib_cmap_adjust_int.header.id = MESSAGE_REQ_CMAP_ADJUST_INT;
+
+ memcpy(req_lib_cmap_adjust_int.key_name.value, key_name, strlen(key_name));
+ req_lib_cmap_adjust_int.key_name.length = strlen(key_name);
+
+ req_lib_cmap_adjust_int.step = step;
+
+ iov.iov_base = (char *)&req_lib_cmap_adjust_int;
+ iov.iov_len = sizeof(req_lib_cmap_adjust_int);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_adjust_int,
+ sizeof (struct res_lib_cmap_adjust_int), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_adjust_int.header.error;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_inc(cmap_handle_t handle, const char *key_name)
+{
+
+ return (cmap_adjust_int(handle, key_name, 1));
+}
+
+cs_error_t cmap_dec(cmap_handle_t handle, const char *key_name)
+{
+
+ return (cmap_adjust_int(handle, key_name, -1));
+}
+
+cs_error_t cmap_iter_init(
+ cmap_handle_t handle,
+ const char *prefix,
+ cmap_iter_handle_t *cmap_iter_handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_iter_init req_lib_cmap_iter_init;
+ struct res_lib_cmap_iter_init res_lib_cmap_iter_init;
+
+ if (cmap_iter_handle == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_iter_init, 0, sizeof(req_lib_cmap_iter_init));
+ req_lib_cmap_iter_init.header.size = sizeof(req_lib_cmap_iter_init);
+ req_lib_cmap_iter_init.header.id = MESSAGE_REQ_CMAP_ITER_INIT;
+
+ if (prefix) {
+ if (strlen(prefix) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+ memcpy(req_lib_cmap_iter_init.prefix.value, prefix, strlen(prefix));
+ req_lib_cmap_iter_init.prefix.length = strlen(prefix);
+ }
+
+ iov.iov_base = (char *)&req_lib_cmap_iter_init;
+ iov.iov_len = sizeof(req_lib_cmap_iter_init);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_iter_init,
+ sizeof (struct res_lib_cmap_iter_init), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_iter_init.header.error;
+ }
+
+ if (error == CS_OK) {
+ *cmap_iter_handle = res_lib_cmap_iter_init.iter_handle;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_iter_next(
+ cmap_handle_t handle,
+ cmap_iter_handle_t iter_handle,
+ char key_name[],
+ size_t *value_len,
+ cmap_value_types_t *type)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_iter_next req_lib_cmap_iter_next;
+ struct res_lib_cmap_iter_next res_lib_cmap_iter_next;
+
+ if (key_name == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_iter_next, 0, sizeof(req_lib_cmap_iter_next));
+ req_lib_cmap_iter_next.header.size = sizeof(req_lib_cmap_iter_next);
+ req_lib_cmap_iter_next.header.id = MESSAGE_REQ_CMAP_ITER_NEXT;
+ req_lib_cmap_iter_next.iter_handle = iter_handle;
+
+ iov.iov_base = (char *)&req_lib_cmap_iter_next;
+ iov.iov_len = sizeof(req_lib_cmap_iter_next);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_iter_next,
+ sizeof (struct res_lib_cmap_iter_next), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_iter_next.header.error;
+ }
+
+ if (error == CS_OK) {
+ memcpy(key_name, (const char *)res_lib_cmap_iter_next.key_name.value,
+ res_lib_cmap_iter_next.key_name.length);
+ key_name[res_lib_cmap_iter_next.key_name.length] = '\0';
+
+ if (value_len != NULL) {
+ *value_len = res_lib_cmap_iter_next.value_len;
+ }
+
+ if (type != NULL) {
+ *type = res_lib_cmap_iter_next.type;
+ }
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_iter_finalize(
+ cmap_handle_t handle,
+ cmap_iter_handle_t iter_handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_iter_finalize req_lib_cmap_iter_finalize;
+ struct res_lib_cmap_iter_finalize res_lib_cmap_iter_finalize;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_iter_finalize, 0, sizeof(req_lib_cmap_iter_finalize));
+ req_lib_cmap_iter_finalize.header.size = sizeof(req_lib_cmap_iter_finalize);
+ req_lib_cmap_iter_finalize.header.id = MESSAGE_REQ_CMAP_ITER_FINALIZE;
+ req_lib_cmap_iter_finalize.iter_handle = iter_handle;
+
+ iov.iov_base = (char *)&req_lib_cmap_iter_finalize;
+ iov.iov_len = sizeof(req_lib_cmap_iter_finalize);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_iter_finalize,
+ sizeof (struct res_lib_cmap_iter_finalize), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_iter_finalize.header.error;
+ }
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_track_add(
+ cmap_handle_t handle,
+ const char *key_name,
+ int32_t track_type,
+ cmap_notify_fn_t notify_fn,
+ void *user_data,
+ cmap_track_handle_t *cmap_track_handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct req_lib_cmap_track_add req_lib_cmap_track_add;
+ struct res_lib_cmap_track_add res_lib_cmap_track_add;
+ struct cmap_track_inst *cmap_track_inst;
+ cmap_track_handle_t cmap_track_inst_handle;
+
+ if (cmap_track_handle == NULL || notify_fn == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_create(&cmap_track_handle_t_db,
+ sizeof(*cmap_track_inst), &cmap_track_inst_handle));
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db,
+ cmap_track_inst_handle, (void *)&cmap_track_inst));
+ if (error != CS_OK) {
+ goto error_put_destroy;
+ }
+
+ cmap_track_inst->user_data = user_data;
+ cmap_track_inst->notify_fn = notify_fn;
+ cmap_track_inst->c = cmap_inst->c;
+
+ memset(&req_lib_cmap_track_add, 0, sizeof(req_lib_cmap_track_add));
+ req_lib_cmap_track_add.header.size = sizeof(req_lib_cmap_track_add);
+ req_lib_cmap_track_add.header.id = MESSAGE_REQ_CMAP_TRACK_ADD;
+
+ if (key_name) {
+ if (strlen(key_name) >= CS_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+ memcpy(req_lib_cmap_track_add.key_name.value, key_name, strlen(key_name));
+ req_lib_cmap_track_add.key_name.length = strlen(key_name);
+ }
+
+ req_lib_cmap_track_add.track_type = track_type;
+ req_lib_cmap_track_add.track_inst_handle = cmap_track_inst_handle;
+
+ iov.iov_base = (char *)&req_lib_cmap_track_add;
+ iov.iov_len = sizeof(req_lib_cmap_track_add);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_track_add,
+ sizeof (struct res_lib_cmap_track_add), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_track_add.header.error;
+ }
+
+ if (error == CS_OK) {
+ *cmap_track_handle = res_lib_cmap_track_add.track_handle;
+ cmap_track_inst->track_handle = *cmap_track_handle;
+ }
+
+ (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle);
+
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+
+error_put_destroy:
+ (void)hdb_handle_put (&cmap_track_handle_t_db, cmap_track_inst_handle);
+ (void)hdb_handle_destroy (&cmap_track_handle_t_db, cmap_track_inst_handle);
+
+error_put:
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cmap_track_delete(
+ cmap_handle_t handle,
+ cmap_track_handle_t track_handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cmap_inst *cmap_inst;
+ struct cmap_track_inst *cmap_track_inst;
+ struct req_lib_cmap_track_delete req_lib_cmap_track_delete;
+ struct res_lib_cmap_track_delete res_lib_cmap_track_delete;
+
+ error = hdb_error_to_cs(hdb_handle_get (&cmap_handle_t_db, handle, (void *)&cmap_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ memset(&req_lib_cmap_track_delete, 0, sizeof(req_lib_cmap_track_delete));
+ req_lib_cmap_track_delete.header.size = sizeof(req_lib_cmap_track_delete);
+ req_lib_cmap_track_delete.header.id = MESSAGE_REQ_CMAP_TRACK_DELETE;
+ req_lib_cmap_track_delete.track_handle = track_handle;
+
+ iov.iov_base = (char *)&req_lib_cmap_track_delete;
+ iov.iov_len = sizeof(req_lib_cmap_track_delete);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv(
+ cmap_inst->c,
+ &iov,
+ 1,
+ &res_lib_cmap_track_delete,
+ sizeof (struct res_lib_cmap_track_delete), CS_IPC_TIMEOUT_MS));
+
+ if (error == CS_OK) {
+ error = res_lib_cmap_track_delete.header.error;
+ }
+
+ if (error == CS_OK) {
+ error = hdb_error_to_cs(hdb_handle_get(&cmap_track_handle_t_db,
+ res_lib_cmap_track_delete.track_inst_handle,
+ (void *)&cmap_track_inst));
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ (void)hdb_handle_put(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle);
+ (void)hdb_handle_destroy(&cmap_track_handle_t_db, res_lib_cmap_track_delete.track_inst_handle);
+ }
+
+error_put:
+ (void)hdb_handle_put (&cmap_handle_t_db, handle);
+
+ return (error);
+}
diff --git a/lib/cpg.c b/lib/cpg.c
new file mode 100644
index 0000000..b41f31d
--- /dev/null
+++ b/lib/cpg.c
@@ -0,0 +1,1426 @@
+/*
+ * vi: set autoindent tabstop=4 shiftwidth=4 :
+ *
+ * Copyright (c) 2006-2015 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Christine Caulfield (ccaulfi@redhat.com)
+ * Author: Jan Friesse (jfriesse@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Provides a closed process group API using the coroipcc executive
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <qb/qblist.h>
+#include <qb/qbdefs.h>
+#include <qb/qbipcc.h>
+#include <qb/qblog.h>
+
+#include <corosync/hdb.h>
+#include <corosync/corotypes.h>
+#include <corosync/corodefs.h>
+#include <corosync/cpg.h>
+#include <corosync/ipc_cpg.h>
+
+#include "util.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/*
+ * Maximum number of times to retry a send when transmitting
+ * a large message fragment
+ */
+#define MAX_RETRIES 100
+
+/*
+ * ZCB files have following umask (umask is same as used in libqb)
+ */
+#define CPG_MEMORY_MAP_UMASK 077
+
+struct cpg_assembly_data
+{
+ struct qb_list_head list;
+ uint32_t nodeid;
+ uint32_t pid;
+ char *assembly_buf;
+ uint32_t assembly_buf_ptr;
+};
+
+struct cpg_inst {
+ qb_ipcc_connection_t *c;
+ int finalize;
+ void *context;
+ union {
+ cpg_model_data_t model_data;
+ cpg_model_v1_data_t model_v1_data;
+ };
+ struct qb_list_head iteration_list_head;
+ uint32_t max_msg_size;
+ struct qb_list_head assembly_list_head;
+};
+static void cpg_inst_free (void *inst);
+
+DECLARE_HDB_DATABASE(cpg_handle_t_db, cpg_inst_free);
+
+struct cpg_iteration_instance_t {
+ cpg_iteration_handle_t cpg_iteration_handle;
+ qb_ipcc_connection_t *conn;
+ hdb_handle_t executive_iteration_handle;
+ struct qb_list_head list;
+};
+
+DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL);
+
+
+/*
+ * Internal (not visible by API) functions
+ */
+
+static cs_error_t
+coroipcc_msg_send_reply_receive (
+ qb_ipcc_connection_t *c,
+ const struct iovec *iov,
+ unsigned int iov_len,
+ void *res_msg,
+ size_t res_len)
+{
+ return qb_to_cs_error(qb_ipcc_sendv_recv(c, iov, iov_len, res_msg, res_len,
+ CS_IPC_TIMEOUT_MS));
+}
+
+static void cpg_iteration_instance_finalize (struct cpg_iteration_instance_t *cpg_iteration_instance)
+{
+ qb_list_del (&cpg_iteration_instance->list);
+ hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
+}
+
+static void cpg_inst_free (void *inst)
+{
+ struct cpg_inst *cpg_inst = (struct cpg_inst *)inst;
+ qb_ipcc_disconnect(cpg_inst->c);
+}
+
+static void cpg_inst_finalize (struct cpg_inst *cpg_inst, hdb_handle_t handle)
+{
+ struct qb_list_head *iter, *tmp_iter;
+ struct cpg_iteration_instance_t *cpg_iteration_instance;
+
+ /*
+ * Traverse thru iteration instances and delete them
+ */
+ qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->iteration_list_head)) {
+ cpg_iteration_instance = qb_list_entry (iter, struct cpg_iteration_instance_t, list);
+
+ cpg_iteration_instance_finalize (cpg_iteration_instance);
+ }
+ hdb_handle_destroy (&cpg_handle_t_db, handle);
+}
+
+/**
+ * @defgroup cpg_coroipcc The closed process group API
+ * @ingroup coroipcc
+ *
+ * @{
+ */
+
+cs_error_t cpg_initialize (
+ cpg_handle_t *handle,
+ cpg_callbacks_t *callbacks)
+{
+ cpg_model_v1_data_t model_v1_data;
+
+ memset (&model_v1_data, 0, sizeof (cpg_model_v1_data_t));
+
+ if (callbacks) {
+ model_v1_data.cpg_deliver_fn = callbacks->cpg_deliver_fn;
+ model_v1_data.cpg_confchg_fn = callbacks->cpg_confchg_fn;
+ }
+
+ return (cpg_model_initialize (handle, CPG_MODEL_V1, (cpg_model_data_t *)&model_v1_data, NULL));
+}
+
+cs_error_t cpg_model_initialize (
+ cpg_handle_t *handle,
+ cpg_model_t model,
+ cpg_model_data_t *model_data,
+ void *context)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ if (model != CPG_MODEL_V1) {
+ error = CS_ERR_INVALID_PARAM;
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs (hdb_handle_create (&cpg_handle_t_db, sizeof (struct cpg_inst), handle));
+ if (error != CS_OK) {
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, *handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ cpg_inst->c = qb_ipcc_connect ("cpg", IPC_REQUEST_SIZE);
+ if (cpg_inst->c == NULL) {
+ error = qb_to_cs_error(-errno);
+ goto error_put_destroy;
+ }
+
+ if (model_data != NULL) {
+ switch (model) {
+ case CPG_MODEL_V1:
+ memcpy (&cpg_inst->model_v1_data, model_data, sizeof (cpg_model_v1_data_t));
+ if ((cpg_inst->model_v1_data.flags & ~(CPG_MODEL_V1_DELIVER_INITIAL_TOTEM_CONF)) != 0) {
+ error = CS_ERR_INVALID_PARAM;
+
+ goto error_destroy;
+ }
+ break;
+ }
+ }
+
+ /* Allow space for corosync internal headers */
+ cpg_inst->max_msg_size = IPC_REQUEST_SIZE - 1024;
+ cpg_inst->model_data.model = model;
+ cpg_inst->context = context;
+
+ qb_list_init(&cpg_inst->iteration_list_head);
+
+ qb_list_init(&cpg_inst->assembly_list_head);
+
+ hdb_handle_put (&cpg_handle_t_db, *handle);
+
+ return (CS_OK);
+
+error_put_destroy:
+ hdb_handle_put (&cpg_handle_t_db, *handle);
+error_destroy:
+ hdb_handle_destroy (&cpg_handle_t_db, *handle);
+error_no_destroy:
+ return (error);
+}
+
+cs_error_t cpg_finalize (
+ cpg_handle_t handle)
+{
+ struct cpg_inst *cpg_inst;
+ struct iovec iov;
+ struct req_lib_cpg_finalize req_lib_cpg_finalize;
+ struct res_lib_cpg_finalize res_lib_cpg_finalize;
+ cs_error_t error;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Another thread has already started finalizing
+ */
+ if (cpg_inst->finalize) {
+ hdb_handle_put (&cpg_handle_t_db, handle);
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ cpg_inst->finalize = 1;
+
+ /*
+ * Send service request
+ */
+ req_lib_cpg_finalize.header.size = sizeof (struct req_lib_cpg_finalize);
+ req_lib_cpg_finalize.header.id = MESSAGE_REQ_CPG_FINALIZE;
+
+ iov.iov_base = (void *)&req_lib_cpg_finalize;
+ iov.iov_len = sizeof (struct req_lib_cpg_finalize);
+
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cpg_finalize,
+ sizeof (struct res_lib_cpg_finalize));
+
+ cpg_inst_finalize (cpg_inst, handle);
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_fd_get (
+ cpg_handle_t handle,
+ int *fd)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = qb_to_cs_error (qb_ipcc_fd_get (cpg_inst->c, fd));
+
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_max_atomic_msgsize_get (
+ cpg_handle_t handle,
+ uint32_t *size)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ *size = cpg_inst->max_msg_size;
+
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_context_get (
+ cpg_handle_t handle,
+ void **context)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ *context = cpg_inst->context;
+
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t cpg_context_set (
+ cpg_handle_t handle,
+ void *context)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ cpg_inst->context = context;
+
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t cpg_dispatch (
+ cpg_handle_t handle,
+ cs_dispatch_flags_t dispatch_types)
+{
+ int timeout = -1;
+ cs_error_t error;
+ int cont = 1; /* always continue do loop except when set to 0 */
+ struct cpg_inst *cpg_inst;
+ struct res_lib_cpg_confchg_callback *res_cpg_confchg_callback;
+ struct res_lib_cpg_deliver_callback *res_cpg_deliver_callback;
+ struct res_lib_cpg_partial_deliver_callback *res_cpg_partial_deliver_callback;
+ struct res_lib_cpg_totem_confchg_callback *res_cpg_totem_confchg_callback;
+ struct cpg_inst cpg_inst_copy;
+ struct qb_ipc_response_header *dispatch_data;
+ struct cpg_address member_list[CPG_MEMBERS_MAX];
+ struct cpg_address left_list[CPG_MEMBERS_MAX];
+ struct cpg_address joined_list[CPG_MEMBERS_MAX];
+ struct cpg_name group_name;
+ struct cpg_assembly_data *assembly_data;
+ struct qb_list_head *iter, *tmp_iter;
+ mar_cpg_address_t *left_list_start;
+ mar_cpg_address_t *joined_list_start;
+ unsigned int i;
+ struct cpg_ring_id ring_id;
+ uint32_t totem_member_list[CPG_MEMBERS_MAX];
+ int32_t errno_res;
+ char dispatch_buf[IPC_DISPATCH_SIZE];
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
+ * wait indefinitely for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
+ */
+ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ timeout = 0;
+ }
+
+ dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
+ do {
+ errno_res = qb_ipcc_event_recv (
+ cpg_inst->c,
+ dispatch_buf,
+ IPC_DISPATCH_SIZE,
+ timeout);
+ error = qb_to_cs_error (errno_res);
+ if (error == CS_ERR_BAD_HANDLE) {
+ error = CS_OK;
+ goto error_put;
+ }
+ if (error == CS_ERR_TRY_AGAIN) {
+ if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ /*
+ * Don't mask error
+ */
+ goto error_put;
+ }
+ error = CS_OK;
+ if (dispatch_types == CS_DISPATCH_ALL) {
+ break; /* exit do while cont is 1 loop */
+ } else {
+ continue; /* next poll */
+ }
+ }
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ /*
+ * Make copy of callbacks, message data, unlock instance, and call callback
+ * A risk of this dispatch method is that the callback routines may
+ * operate at the same time that cpgFinalize has been called.
+ */
+ memcpy (&cpg_inst_copy, cpg_inst, sizeof (struct cpg_inst));
+ switch (cpg_inst_copy.model_data.model) {
+ case CPG_MODEL_V1:
+ /*
+ * Dispatch incoming message
+ */
+ switch (dispatch_data->id) {
+ case MESSAGE_RES_CPG_DELIVER_CALLBACK:
+ if (cpg_inst_copy.model_v1_data.cpg_deliver_fn == NULL) {
+ break;
+ }
+
+ res_cpg_deliver_callback = (struct res_lib_cpg_deliver_callback *)dispatch_data;
+
+ marshall_from_mar_cpg_name_t (
+ &group_name,
+ &res_cpg_deliver_callback->group_name);
+
+ cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle,
+ &group_name,
+ res_cpg_deliver_callback->nodeid,
+ res_cpg_deliver_callback->pid,
+ &res_cpg_deliver_callback->message,
+ res_cpg_deliver_callback->msglen);
+ break;
+
+ case MESSAGE_RES_CPG_PARTIAL_DELIVER_CALLBACK:
+ res_cpg_partial_deliver_callback = (struct res_lib_cpg_partial_deliver_callback *)dispatch_data;
+
+ marshall_from_mar_cpg_name_t (
+ &group_name,
+ &res_cpg_partial_deliver_callback->group_name);
+
+ /*
+ * Search for assembly data for current messages (nodeid, pid) pair in list of assemblies
+ */
+ assembly_data = NULL;
+ qb_list_for_each(iter, &(cpg_inst->assembly_list_head)) {
+ struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list);
+ if (current_assembly_data->nodeid == res_cpg_partial_deliver_callback->nodeid && current_assembly_data->pid == res_cpg_partial_deliver_callback->pid) {
+ assembly_data = current_assembly_data;
+ break;
+ }
+ }
+
+ if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_FIRST) {
+
+ /*
+ * As this is LIBCPG_PARTIAL_FIRST packet, check that there is no ongoing assembly.
+ * Otherwise the sending of packet must have been interrupted and error should have
+ * been reported to sending client. Therefore here last assembly will be dropped.
+ */
+ if (assembly_data) {
+ qb_list_del (&assembly_data->list);
+ free(assembly_data->assembly_buf);
+ free(assembly_data);
+ assembly_data = NULL;
+ }
+
+ assembly_data = malloc(sizeof(struct cpg_assembly_data));
+ if (!assembly_data) {
+ error = CS_ERR_NO_MEMORY;
+ goto error_put;
+ }
+
+ assembly_data->nodeid = res_cpg_partial_deliver_callback->nodeid;
+ assembly_data->pid = res_cpg_partial_deliver_callback->pid;
+ assembly_data->assembly_buf = malloc(res_cpg_partial_deliver_callback->msglen);
+ if (!assembly_data->assembly_buf) {
+ free(assembly_data);
+ error = CS_ERR_NO_MEMORY;
+ goto error_put;
+ }
+ assembly_data->assembly_buf_ptr = 0;
+ qb_list_init (&assembly_data->list);
+
+ qb_list_add (&assembly_data->list, &cpg_inst->assembly_list_head);
+ }
+ if (assembly_data) {
+ memcpy(assembly_data->assembly_buf + assembly_data->assembly_buf_ptr,
+ res_cpg_partial_deliver_callback->message, res_cpg_partial_deliver_callback->fraglen);
+ assembly_data->assembly_buf_ptr += res_cpg_partial_deliver_callback->fraglen;
+
+ if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_LAST) {
+ cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle,
+ &group_name,
+ res_cpg_partial_deliver_callback->nodeid,
+ res_cpg_partial_deliver_callback->pid,
+ assembly_data->assembly_buf,
+ res_cpg_partial_deliver_callback->msglen);
+
+ qb_list_del (&assembly_data->list);
+ free(assembly_data->assembly_buf);
+ free(assembly_data);
+ }
+ }
+ break;
+
+ case MESSAGE_RES_CPG_CONFCHG_CALLBACK:
+ if (cpg_inst_copy.model_v1_data.cpg_confchg_fn == NULL) {
+ break;
+ }
+
+ res_cpg_confchg_callback = (struct res_lib_cpg_confchg_callback *)dispatch_data;
+
+ for (i = 0; i < res_cpg_confchg_callback->member_list_entries; i++) {
+ marshall_from_mar_cpg_address_t (&member_list[i],
+ &res_cpg_confchg_callback->member_list[i]);
+ }
+ left_list_start = res_cpg_confchg_callback->member_list +
+ res_cpg_confchg_callback->member_list_entries;
+ for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) {
+ marshall_from_mar_cpg_address_t (&left_list[i],
+ &left_list_start[i]);
+ }
+ joined_list_start = res_cpg_confchg_callback->member_list +
+ res_cpg_confchg_callback->member_list_entries +
+ res_cpg_confchg_callback->left_list_entries;
+ for (i = 0; i < res_cpg_confchg_callback->joined_list_entries; i++) {
+ marshall_from_mar_cpg_address_t (&joined_list[i],
+ &joined_list_start[i]);
+ }
+ marshall_from_mar_cpg_name_t (
+ &group_name,
+ &res_cpg_confchg_callback->group_name);
+
+ cpg_inst_copy.model_v1_data.cpg_confchg_fn (handle,
+ &group_name,
+ member_list,
+ res_cpg_confchg_callback->member_list_entries,
+ left_list,
+ res_cpg_confchg_callback->left_list_entries,
+ joined_list,
+ res_cpg_confchg_callback->joined_list_entries);
+
+ /*
+ * If member left while his partial packet was being assembled, assembly data must be removed from list
+ */
+ for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) {
+ qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->assembly_list_head)) {
+ struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list);
+ if (current_assembly_data->nodeid != left_list[i].nodeid || current_assembly_data->pid != left_list[i].pid)
+ continue;
+
+ qb_list_del (&current_assembly_data->list);
+ free(current_assembly_data->assembly_buf);
+ free(current_assembly_data);
+ }
+ }
+
+ break;
+ case MESSAGE_RES_CPG_TOTEM_CONFCHG_CALLBACK:
+ if (cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn == NULL) {
+ break;
+ }
+
+ res_cpg_totem_confchg_callback = (struct res_lib_cpg_totem_confchg_callback *)dispatch_data;
+
+ marshall_from_mar_cpg_ring_id_t (&ring_id, &res_cpg_totem_confchg_callback->ring_id);
+ for (i = 0; i < res_cpg_totem_confchg_callback->member_list_entries; i++) {
+ totem_member_list[i] = res_cpg_totem_confchg_callback->member_list[i];
+ }
+
+ cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn (handle,
+ ring_id,
+ res_cpg_totem_confchg_callback->member_list_entries,
+ totem_member_list);
+ break;
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_put;
+ break;
+ } /* - switch (dispatch_data->id) */
+ break; /* case CPG_MODEL_V1 */
+ } /* - switch (cpg_inst_copy.model_data.model) */
+
+ if (cpg_inst_copy.finalize || cpg_inst->finalize) {
+ /*
+ * If the finalize has been called then get out of the dispatch.
+ */
+ cpg_inst->finalize = 1;
+ error = CS_ERR_BAD_HANDLE;
+ goto error_put;
+ }
+
+ /*
+ * Determine if more messages should be processed
+ */
+ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ cont = 0;
+ }
+ } while (cont);
+
+error_put:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+ return (error);
+}
+
+cs_error_t cpg_join (
+ cpg_handle_t handle,
+ const struct cpg_name *group)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct iovec iov[2];
+ struct req_lib_cpg_join req_lib_cpg_join;
+ struct res_lib_cpg_join response;
+
+ if (group->length > CPG_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /* Now join */
+ req_lib_cpg_join.header.size = sizeof (struct req_lib_cpg_join);
+ req_lib_cpg_join.header.id = MESSAGE_REQ_CPG_JOIN;
+ req_lib_cpg_join.pid = getpid();
+ req_lib_cpg_join.flags = 0;
+
+ switch (cpg_inst->model_data.model) {
+ case CPG_MODEL_V1:
+ req_lib_cpg_join.flags = cpg_inst->model_v1_data.flags;
+ break;
+ }
+
+ marshall_to_mar_cpg_name_t (&req_lib_cpg_join.group_name,
+ group);
+
+ iov[0].iov_base = (void *)&req_lib_cpg_join;
+ iov[0].iov_len = sizeof (struct req_lib_cpg_join);
+
+ do {
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1,
+ &response, sizeof (struct res_lib_cpg_join));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+ } while (response.header.error == CS_ERR_BUSY);
+
+ error = response.header.error;
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_leave (
+ cpg_handle_t handle,
+ const struct cpg_name *group)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct iovec iov[2];
+ struct req_lib_cpg_leave req_lib_cpg_leave;
+ struct res_lib_cpg_leave res_lib_cpg_leave;
+
+ if (group->length > CPG_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cpg_leave.header.size = sizeof (struct req_lib_cpg_leave);
+ req_lib_cpg_leave.header.id = MESSAGE_REQ_CPG_LEAVE;
+ req_lib_cpg_leave.pid = getpid();
+ marshall_to_mar_cpg_name_t (&req_lib_cpg_leave.group_name,
+ group);
+
+ iov[0].iov_base = (void *)&req_lib_cpg_leave;
+ iov[0].iov_len = sizeof (struct req_lib_cpg_leave);
+
+ do {
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1,
+ &res_lib_cpg_leave, sizeof (struct res_lib_cpg_leave));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+ } while (res_lib_cpg_leave.header.error == CS_ERR_BUSY);
+
+ error = res_lib_cpg_leave.header.error;
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_membership_get (
+ cpg_handle_t handle,
+ struct cpg_name *group_name,
+ struct cpg_address *member_list,
+ int *member_list_entries)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct iovec iov;
+ struct req_lib_cpg_membership_get req_lib_cpg_membership_get;
+ struct res_lib_cpg_membership_get res_lib_cpg_membership_get;
+ unsigned int i;
+
+ if (group_name->length > CPG_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+ if (member_list == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+ if (member_list_entries == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cpg_membership_get.header.size = sizeof (struct req_lib_cpg_membership_get);
+ req_lib_cpg_membership_get.header.id = MESSAGE_REQ_CPG_MEMBERSHIP;
+
+ marshall_to_mar_cpg_name_t (&req_lib_cpg_membership_get.group_name,
+ group_name);
+
+ iov.iov_base = (void *)&req_lib_cpg_membership_get;
+ iov.iov_len = sizeof (struct req_lib_cpg_membership_get);
+
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1,
+ &res_lib_cpg_membership_get, sizeof (res_lib_cpg_membership_get));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cpg_membership_get.header.error;
+
+ /*
+ * Copy results to caller
+ */
+ *member_list_entries = res_lib_cpg_membership_get.member_count;
+ if (member_list) {
+ for (i = 0; i < res_lib_cpg_membership_get.member_count; i++) {
+ marshall_from_mar_cpg_address_t (&member_list[i],
+ &res_lib_cpg_membership_get.member_list[i]);
+ }
+ }
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_local_get (
+ cpg_handle_t handle,
+ unsigned int *local_nodeid)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct iovec iov;
+ struct req_lib_cpg_local_get req_lib_cpg_local_get;
+ struct res_lib_cpg_local_get res_lib_cpg_local_get;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_cpg_local_get.header.size = sizeof (struct qb_ipc_request_header);
+ req_lib_cpg_local_get.header.id = MESSAGE_REQ_CPG_LOCAL_GET;
+
+ iov.iov_base = (void *)&req_lib_cpg_local_get;
+ iov.iov_len = sizeof (struct req_lib_cpg_local_get);
+
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1,
+ &res_lib_cpg_local_get, sizeof (res_lib_cpg_local_get));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cpg_local_get.header.error;
+
+ *local_nodeid = res_lib_cpg_local_get.local_nodeid;
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_flow_control_state_get (
+ cpg_handle_t handle,
+ cpg_flow_control_state_t *flow_control_state)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+ *flow_control_state = CPG_FLOW_CONTROL_DISABLED;
+ error = CS_OK;
+
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+static int
+memory_map (char *path, const char *file, void **buf, size_t bytes)
+{
+ int32_t fd;
+ void *addr;
+ int32_t res;
+ char *buffer;
+ int32_t i;
+ size_t written;
+ size_t page_size;
+ long int sysconf_page_size;
+ mode_t old_umask;
+
+ snprintf (path, PATH_MAX, "/dev/shm/%s", file);
+
+ old_umask = umask(CPG_MEMORY_MAP_UMASK);
+ fd = mkstemp (path);
+ (void)umask(old_umask);
+ if (fd == -1) {
+ snprintf (path, PATH_MAX, LOCALSTATEDIR "/run/%s", file);
+ old_umask = umask(CPG_MEMORY_MAP_UMASK);
+ fd = mkstemp (path);
+ (void)umask(old_umask);
+ if (fd == -1) {
+ return (-1);
+ }
+ }
+
+ res = ftruncate (fd, bytes);
+ if (res == -1) {
+ goto error_close_unlink;
+ }
+ sysconf_page_size = sysconf(_SC_PAGESIZE);
+ if (sysconf_page_size <= 0) {
+ goto error_close_unlink;
+ }
+ page_size = sysconf_page_size;
+ buffer = malloc (page_size);
+ if (buffer == NULL) {
+ goto error_close_unlink;
+ }
+ memset (buffer, 0, page_size);
+ for (i = 0; i < (bytes / page_size); i++) {
+retry_write:
+ written = write (fd, buffer, page_size);
+ if (written == -1 && errno == EINTR) {
+ goto retry_write;
+ }
+ if (written != page_size) {
+ free (buffer);
+ goto error_close_unlink;
+ }
+ }
+ free (buffer);
+
+ addr = mmap (NULL, bytes, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, 0);
+
+ if (addr == MAP_FAILED) {
+ goto error_close_unlink;
+ }
+#ifdef MADV_NOSYNC
+ madvise(addr, bytes, MADV_NOSYNC);
+#endif
+
+ res = close (fd);
+ if (res) {
+ munmap(addr, bytes);
+
+ return (-1);
+ }
+ *buf = addr;
+
+ return 0;
+
+error_close_unlink:
+ close (fd);
+ unlink(path);
+ return -1;
+}
+
+cs_error_t cpg_zcb_alloc (
+ cpg_handle_t handle,
+ size_t size,
+ void **buffer)
+{
+ void *buf = NULL;
+ char path[PATH_MAX];
+ mar_req_coroipcc_zc_alloc_t req_coroipcc_zc_alloc;
+ struct qb_ipc_response_header res_coroipcs_zc_alloc;
+ size_t map_size;
+ struct iovec iovec;
+ struct coroipcs_zc_header *hdr;
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ map_size = size + sizeof (struct req_lib_cpg_mcast) + sizeof (struct coroipcs_zc_header);
+ assert(memory_map (path, "corosync_zerocopy-XXXXXX", &buf, map_size) != -1);
+
+ if (strlen(path) >= CPG_ZC_PATH_LEN) {
+ unlink(path);
+ munmap (buf, map_size);
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+
+ req_coroipcc_zc_alloc.header.size = sizeof (mar_req_coroipcc_zc_alloc_t);
+ req_coroipcc_zc_alloc.header.id = MESSAGE_REQ_CPG_ZC_ALLOC;
+ req_coroipcc_zc_alloc.map_size = map_size;
+ strcpy (req_coroipcc_zc_alloc.path_to_file, path);
+
+ iovec.iov_base = (void *)&req_coroipcc_zc_alloc;
+ iovec.iov_len = sizeof (mar_req_coroipcc_zc_alloc_t);
+
+ error = coroipcc_msg_send_reply_receive (
+ cpg_inst->c,
+ &iovec,
+ 1,
+ &res_coroipcs_zc_alloc,
+ sizeof (struct qb_ipc_response_header));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ hdr = (struct coroipcs_zc_header *)buf;
+ hdr->map_size = map_size;
+ *buffer = ((char *)buf) + sizeof (struct coroipcs_zc_header) + sizeof (struct req_lib_cpg_mcast);
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+ return (error);
+}
+
+cs_error_t cpg_zcb_free (
+ cpg_handle_t handle,
+ void *buffer)
+{
+ cs_error_t error;
+ unsigned int res;
+ struct cpg_inst *cpg_inst;
+ mar_req_coroipcc_zc_free_t req_coroipcc_zc_free;
+ struct qb_ipc_response_header res_coroipcs_zc_free;
+ struct iovec iovec;
+ struct coroipcs_zc_header *header = (struct coroipcs_zc_header *)((char *)buffer - sizeof (struct coroipcs_zc_header) - sizeof (struct req_lib_cpg_mcast));
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_coroipcc_zc_free.header.size = sizeof (mar_req_coroipcc_zc_free_t);
+ req_coroipcc_zc_free.header.id = MESSAGE_REQ_CPG_ZC_FREE;
+ req_coroipcc_zc_free.map_size = header->map_size;
+ req_coroipcc_zc_free.server_address = header->server_address;
+
+ iovec.iov_base = (void *)&req_coroipcc_zc_free;
+ iovec.iov_len = sizeof (mar_req_coroipcc_zc_free_t);
+
+ error = coroipcc_msg_send_reply_receive (
+ cpg_inst->c,
+ &iovec,
+ 1,
+ &res_coroipcs_zc_free,
+ sizeof (struct qb_ipc_response_header));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ res = munmap ((void *)header, header->map_size);
+ if (res == -1) {
+ error = qb_to_cs_error(-errno);
+
+ goto error_exit;
+ }
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_zcb_mcast_joined (
+ cpg_handle_t handle,
+ cpg_guarantee_t guarantee,
+ void *msg,
+ size_t msg_len)
+{
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct req_lib_cpg_mcast *req_lib_cpg_mcast;
+ struct res_lib_cpg_mcast res_lib_cpg_mcast;
+ mar_req_coroipcc_zc_execute_t req_coroipcc_zc_execute;
+ struct coroipcs_zc_header *hdr;
+ struct iovec iovec;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ if (msg_len > IPC_REQUEST_SIZE) {
+ error = CS_ERR_TOO_BIG;
+ goto error_exit;
+ }
+
+ req_lib_cpg_mcast = (struct req_lib_cpg_mcast *)(((char *)msg) - sizeof (struct req_lib_cpg_mcast));
+ req_lib_cpg_mcast->header.size = sizeof (struct req_lib_cpg_mcast) +
+ msg_len;
+
+ req_lib_cpg_mcast->header.id = MESSAGE_REQ_CPG_MCAST;
+ req_lib_cpg_mcast->guarantee = guarantee;
+ req_lib_cpg_mcast->msglen = msg_len;
+
+ hdr = (struct coroipcs_zc_header *)(((char *)req_lib_cpg_mcast) - sizeof (struct coroipcs_zc_header));
+
+ req_coroipcc_zc_execute.header.size = sizeof (mar_req_coroipcc_zc_execute_t);
+ req_coroipcc_zc_execute.header.id = MESSAGE_REQ_CPG_ZC_EXECUTE;
+ req_coroipcc_zc_execute.server_address = hdr->server_address;
+
+ iovec.iov_base = (void *)&req_coroipcc_zc_execute;
+ iovec.iov_len = sizeof (mar_req_coroipcc_zc_execute_t);
+
+ error = coroipcc_msg_send_reply_receive (
+ cpg_inst->c,
+ &iovec,
+ 1,
+ &res_lib_cpg_mcast,
+ sizeof(res_lib_cpg_mcast));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_cpg_mcast.header.error;
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+static cs_error_t send_fragments (
+ struct cpg_inst *cpg_inst,
+ cpg_guarantee_t guarantee,
+ size_t msg_len,
+ const struct iovec *iovec,
+ unsigned int iov_len)
+{
+ int i;
+ cs_error_t error = CS_OK;
+ struct iovec iov[2];
+ struct req_lib_cpg_partial_mcast req_lib_cpg_mcast;
+ struct res_lib_cpg_partial_send res_lib_cpg_partial_send;
+ size_t sent = 0;
+ size_t iov_sent = 0;
+ int retry_count;
+
+ req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_PARTIAL_MCAST;
+ req_lib_cpg_mcast.guarantee = guarantee;
+ req_lib_cpg_mcast.msglen = msg_len;
+
+ iov[0].iov_base = (void *)&req_lib_cpg_mcast;
+ iov[0].iov_len = sizeof (struct req_lib_cpg_partial_mcast);
+
+ i=0;
+ iov_sent = 0 ;
+ qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
+
+ while (error == CS_OK && sent < msg_len) {
+
+ retry_count = 0;
+ if ( (iovec[i].iov_len - iov_sent) > cpg_inst->max_msg_size) {
+ iov[1].iov_len = cpg_inst->max_msg_size;
+ }
+ else {
+ iov[1].iov_len = iovec[i].iov_len - iov_sent;
+ }
+
+ if (sent == 0) {
+ req_lib_cpg_mcast.type = LIBCPG_PARTIAL_FIRST;
+ }
+ else if ((sent + iov[1].iov_len) == msg_len) {
+ req_lib_cpg_mcast.type = LIBCPG_PARTIAL_LAST;
+ }
+ else {
+ req_lib_cpg_mcast.type = LIBCPG_PARTIAL_CONTINUED;
+ }
+
+ req_lib_cpg_mcast.fraglen = iov[1].iov_len;
+ req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_partial_mcast) + iov[1].iov_len;
+ iov[1].iov_base = (char *)iovec[i].iov_base + iov_sent;
+
+ resend:
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 2,
+ &res_lib_cpg_partial_send,
+ sizeof (res_lib_cpg_partial_send));
+
+ if (error == CS_ERR_TRY_AGAIN) {
+ fprintf(stderr, "sleep. counter=%d\n", retry_count);
+ if (++retry_count > MAX_RETRIES) {
+ goto error_exit;
+ }
+ usleep(10000);
+ goto resend;
+ }
+
+ iov_sent += iov[1].iov_len;
+ sent += iov[1].iov_len;
+
+ /* Next iovec */
+ if (iov_sent >= iovec[i].iov_len) {
+ i++;
+ iov_sent = 0;
+ }
+ error = res_lib_cpg_partial_send.header.error;
+ }
+error_exit:
+ qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
+
+ return error;
+}
+
+
+cs_error_t cpg_mcast_joined (
+ cpg_handle_t handle,
+ cpg_guarantee_t guarantee,
+ const struct iovec *iovec,
+ unsigned int iov_len)
+{
+ int i;
+ cs_error_t error;
+ struct cpg_inst *cpg_inst;
+ struct iovec iov[64];
+ struct req_lib_cpg_mcast req_lib_cpg_mcast;
+ size_t msg_len = 0;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ for (i = 0; i < iov_len; i++ ) {
+ msg_len += iovec[i].iov_len;
+ }
+
+ if (msg_len > cpg_inst->max_msg_size) {
+ error = send_fragments(cpg_inst, guarantee, msg_len, iovec, iov_len);
+ goto error_exit;
+ }
+
+ req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_mcast) +
+ msg_len;
+
+ req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_MCAST;
+ req_lib_cpg_mcast.guarantee = guarantee;
+ req_lib_cpg_mcast.msglen = msg_len;
+
+ iov[0].iov_base = (void *)&req_lib_cpg_mcast;
+ iov[0].iov_len = sizeof (struct req_lib_cpg_mcast);
+ memcpy (&iov[1], iovec, iov_len * sizeof (struct iovec));
+
+ qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
+ error = qb_to_cs_error(qb_ipcc_sendv(cpg_inst->c, iov, iov_len + 1));
+ qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
+
+error_exit:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_iteration_initialize(
+ cpg_handle_t handle,
+ cpg_iteration_type_t iteration_type,
+ const struct cpg_name *group,
+ cpg_iteration_handle_t *cpg_iteration_handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cpg_inst *cpg_inst;
+ struct cpg_iteration_instance_t *cpg_iteration_instance;
+ struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize;
+ struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize;
+
+ if (group && group->length > CPG_MAX_NAME_LENGTH) {
+ return (CS_ERR_NAME_TOO_LONG);
+ }
+ if (cpg_iteration_handle == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) ||
+ (iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP &&
+ iteration_type != CPG_ITERATION_ALL) {
+
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db,
+ sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle));
+ if (error != CS_OK) {
+ goto error_put_cpg_db;
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle,
+ (void *)&cpg_iteration_instance));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ cpg_iteration_instance->conn = cpg_inst->c;
+
+ qb_list_init (&cpg_iteration_instance->list);
+
+ req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize);
+ req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE;
+ req_lib_cpg_iterationinitialize.iteration_type = iteration_type;
+ if (group) {
+ marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group);
+ }
+
+ iov.iov_base = (void *)&req_lib_cpg_iterationinitialize;
+ iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize);
+
+ error = coroipcc_msg_send_reply_receive (cpg_inst->c,
+ &iov,
+ 1,
+ &res_lib_cpg_iterationinitialize,
+ sizeof (struct res_lib_cpg_iterationinitialize));
+
+ if (error != CS_OK) {
+ goto error_put_destroy;
+ }
+
+ cpg_iteration_instance->executive_iteration_handle =
+ res_lib_cpg_iterationinitialize.iteration_handle;
+ cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle;
+
+ qb_list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head);
+
+ hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (res_lib_cpg_iterationinitialize.header.error);
+
+error_put_destroy:
+ hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+error_destroy:
+ hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
+error_put_cpg_db:
+ hdb_handle_put (&cpg_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t cpg_iteration_next(
+ cpg_iteration_handle_t handle,
+ struct cpg_iteration_description_t *description)
+{
+ cs_error_t error;
+ struct cpg_iteration_instance_t *cpg_iteration_instance;
+ struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext;
+ struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext;
+
+ if (description == NULL) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
+ (void *)&cpg_iteration_instance));
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext);
+ req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT;
+ req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
+
+ error = qb_to_cs_error (qb_ipcc_send (cpg_iteration_instance->conn,
+ &req_lib_cpg_iterationnext,
+ req_lib_cpg_iterationnext.header.size));
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ error = qb_to_cs_error (qb_ipcc_recv (cpg_iteration_instance->conn,
+ &res_lib_cpg_iterationnext,
+ sizeof(struct res_lib_cpg_iterationnext), -1));
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ marshall_from_mar_cpg_iteration_description_t(
+ description,
+ &res_lib_cpg_iterationnext.description);
+
+ error = res_lib_cpg_iterationnext.header.error;
+
+error_put:
+ hdb_handle_put (&cpg_iteration_handle_t_db, handle);
+
+error_exit:
+ return (error);
+}
+
+cs_error_t cpg_iteration_finalize (
+ cpg_iteration_handle_t handle)
+{
+ cs_error_t error;
+ struct iovec iov;
+ struct cpg_iteration_instance_t *cpg_iteration_instance;
+ struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize;
+ struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize;
+
+ error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
+ (void *)&cpg_iteration_instance));
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize);
+ req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE;
+ req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
+
+ iov.iov_base = (void *)&req_lib_cpg_iterationfinalize;
+ iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize);
+
+ error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn,
+ &iov,
+ 1,
+ &res_lib_cpg_iterationfinalize,
+ sizeof (struct req_lib_cpg_iterationfinalize));
+
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ cpg_iteration_instance_finalize (cpg_iteration_instance);
+ hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
+
+ return (res_lib_cpg_iterationfinalize.header.error);
+
+error_put:
+ hdb_handle_put (&cpg_iteration_handle_t_db, handle);
+error_exit:
+ return (error);
+}
+
+/** @} */
diff --git a/lib/libcfg.versions b/lib/libcfg.versions
new file mode 100644
index 0000000..18d18f7
--- /dev/null
+++ b/lib/libcfg.versions
@@ -0,0 +1,18 @@
+# Version and symbol export for libcfg.so
+
+COROSYNC_CFG_0.82 {
+ global:
+ corosync_cfg_initialize;
+ corosync_cfg_fd_get;
+ corosync_cfg_dispatch;
+ corosync_cfg_finalize;
+ corosync_cfg_administrative_state_get;
+ corosync_cfg_administrative_state_set;
+ corosync_cfg_track;
+ corosync_cfg_track_stop;
+ corosync_cfg_ring_status_get;
+ corosync_cfg_node_status_get;
+ corosync_cfg_ring_reenable;
+ corosync_cfg_trackstart;
+ corosync_cfg_trackstop;
+};
diff --git a/lib/libcfg.verso b/lib/libcfg.verso
new file mode 100644
index 0000000..1502020
--- /dev/null
+++ b/lib/libcfg.verso
@@ -0,0 +1 @@
+7.3.0
diff --git a/lib/libcmap.versions b/lib/libcmap.versions
new file mode 100644
index 0000000..59c8778
--- /dev/null
+++ b/lib/libcmap.versions
@@ -0,0 +1,6 @@
+# Version and symbol export for libsam.so
+
+COROSYNC_CMAP_1.0 {
+ global:
+ cmap_initialize;
+};
diff --git a/lib/libcmap.verso b/lib/libcmap.verso
new file mode 100644
index 0000000..ee74734
--- /dev/null
+++ b/lib/libcmap.verso
@@ -0,0 +1 @@
+4.1.0
diff --git a/lib/libcpg.versions b/lib/libcpg.versions
new file mode 100644
index 0000000..93eeb52
--- /dev/null
+++ b/lib/libcpg.versions
@@ -0,0 +1,17 @@
+# Version and symbol export for libcpg.so
+
+COROSYNC_CPG_1.0 {
+ global:
+ cpg_initialize;
+ cpg_finalize;
+ cpg_fd_get;
+ cpg_dispatch;
+ cpg_join;
+ cpg_leave;
+ cpg_mcast_joined;
+ cpg_membership_get;
+ cpg_context_get;
+ cpg_context_set;
+ cpg_zcb_alloc;
+ cpg_zcb_free;
+};
diff --git a/lib/libcpg.verso b/lib/libcpg.verso
new file mode 100644
index 0000000..ee74734
--- /dev/null
+++ b/lib/libcpg.verso
@@ -0,0 +1 @@
+4.1.0
diff --git a/lib/libquorum.versions b/lib/libquorum.versions
new file mode 100644
index 0000000..b1f0a88
--- /dev/null
+++ b/lib/libquorum.versions
@@ -0,0 +1,11 @@
+# Version and symbol export for libquorum.so
+
+COROSYNC_QUORUM_1.0 {
+ global:
+ quorum_initialize;
+ quorum_finalize;
+ quorum_getquorate;
+ quorum_initialize;
+ quorum_finalize;
+ quorum_dispatch;
+};
diff --git a/lib/libquorum.verso b/lib/libquorum.verso
new file mode 100644
index 0000000..831446c
--- /dev/null
+++ b/lib/libquorum.verso
@@ -0,0 +1 @@
+5.1.0
diff --git a/lib/libsam.versions b/lib/libsam.versions
new file mode 100644
index 0000000..48fba2c
--- /dev/null
+++ b/lib/libsam.versions
@@ -0,0 +1,12 @@
+# Version and symbol export for libsam.so
+
+COROSYNC_SAM_1.0 {
+ global:
+ sam_initialized;
+ sam_finalize;
+ sam_start;
+ sam_stop;
+ sam_register;
+ sam_hc_send;
+ sam_hc_callback_register;
+};
diff --git a/lib/libsam.verso b/lib/libsam.verso
new file mode 100644
index 0000000..fdc6698
--- /dev/null
+++ b/lib/libsam.verso
@@ -0,0 +1 @@
+4.4.0
diff --git a/lib/libvotequorum.versions b/lib/libvotequorum.versions
new file mode 100644
index 0000000..7a37030
--- /dev/null
+++ b/lib/libvotequorum.versions
@@ -0,0 +1,17 @@
+# Version and symbol export for libvotequorum.so
+
+COROSYNC_VOTEQUORUM_1.0 {
+ global:
+ votequorum_initialize;
+ votequorum_finalize;
+ votequorum_getinfo;
+ votequorum_setexpected;
+ votequorum_setvotes;
+ votequorum_qdevice_register;
+ votequorum_qdevice_unregister;
+ votequorum_qdevice_poll;
+ votequorum_trackstart;
+ votequorum_trackstop;
+ votequorum_context_get;
+ votequorum_context_set;
+};
diff --git a/lib/libvotequorum.verso b/lib/libvotequorum.verso
new file mode 100644
index 0000000..ae9a76b
--- /dev/null
+++ b/lib/libvotequorum.verso
@@ -0,0 +1 @@
+8.0.0
diff --git a/lib/quorum.c b/lib/quorum.c
new file mode 100644
index 0000000..c1139c0
--- /dev/null
+++ b/lib/quorum.c
@@ -0,0 +1,588 @@
+/*
+ * Copyright (c) 2008-2020 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Christine Caulfield (ccaulfie@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Provides a quorum API using the corosync executive
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <qb/qbipcc.h>
+#include <corosync/corotypes.h>
+#include <corosync/corodefs.h>
+#include <corosync/hdb.h>
+
+#include <corosync/quorum.h>
+#include <corosync/ipc_quorum.h>
+
+#include "util.h"
+
+struct quorum_inst {
+ qb_ipcc_connection_t *c;
+ int finalize;
+ const void *context;
+ union {
+ quorum_model_data_t model_data;
+ quorum_model_v0_data_t model_v0_data;
+ quorum_model_v1_data_t model_v1_data;
+ };
+};
+
+static void quorum_inst_free (void *inst);
+
+DECLARE_HDB_DATABASE(quorum_handle_t_db, quorum_inst_free);
+
+cs_error_t quorum_initialize (
+ quorum_handle_t *handle,
+ quorum_callbacks_t *callbacks,
+ uint32_t *quorum_type)
+{
+ quorum_model_v0_data_t model_v0_data;
+
+ memset (&model_v0_data, 0, sizeof(quorum_model_v0_data_t));
+
+ if (callbacks) {
+ model_v0_data.quorum_notify_fn = callbacks->quorum_notify_fn;
+ }
+
+ return (quorum_model_initialize(handle, QUORUM_MODEL_V0,
+ (quorum_model_data_t *)&model_v0_data, quorum_type, NULL));
+}
+
+cs_error_t quorum_model_initialize (
+ quorum_handle_t *handle,
+ quorum_model_t model,
+ quorum_model_data_t *model_data,
+ uint32_t *quorum_type,
+ void *context)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+ struct iovec iov;
+ struct qb_ipc_request_header quorum_gettype_req;
+ struct req_lib_quorum_model_gettype quorum_model_gettype_req;
+ struct res_lib_quorum_gettype res_lib_quorum_gettype;
+ struct res_lib_quorum_model_gettype res_lib_quorum_model_gettype;
+ uint32_t local_quorum_type;
+
+ if (model != QUORUM_MODEL_V0 && model != QUORUM_MODEL_V1) {
+ error = CS_ERR_INVALID_PARAM;
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_create (&quorum_handle_t_db, sizeof (struct quorum_inst), handle));
+ if (error != CS_OK) {
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, *handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ error = CS_OK;
+ quorum_inst->finalize = 0;
+ quorum_inst->c = qb_ipcc_connect ("quorum", IPC_REQUEST_SIZE);
+ if (quorum_inst->c == NULL) {
+ error = qb_to_cs_error(-errno);
+ goto error_put_destroy;
+ }
+
+ switch (model) {
+ case QUORUM_MODEL_V0:
+ quorum_gettype_req.size = sizeof (quorum_gettype_req);
+ quorum_gettype_req.id = MESSAGE_REQ_QUORUM_GETTYPE;
+
+ iov.iov_base = (char *)&quorum_gettype_req;
+ iov.iov_len = sizeof (quorum_gettype_req);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ quorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_quorum_gettype,
+ sizeof(res_lib_quorum_gettype), -1));
+
+ if (error != CS_OK) {
+ goto error_put_destroy;
+ }
+ error = res_lib_quorum_gettype.header.error;
+ local_quorum_type = res_lib_quorum_gettype.quorum_type;
+ break;
+ case QUORUM_MODEL_V1:
+ quorum_model_gettype_req.header.size = sizeof (quorum_model_gettype_req);
+ quorum_model_gettype_req.header.id = MESSAGE_REQ_QUORUM_MODEL_GETTYPE;
+ quorum_model_gettype_req.model = model;
+
+ iov.iov_base = (char *)&quorum_model_gettype_req;
+ iov.iov_len = sizeof (quorum_model_gettype_req);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ quorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_quorum_model_gettype,
+ sizeof(res_lib_quorum_model_gettype), -1));
+
+ if (error != CS_OK) {
+ goto error_put_destroy;
+ }
+ error = res_lib_quorum_model_gettype.header.error;
+ local_quorum_type = res_lib_quorum_model_gettype.quorum_type;
+ break;
+ }
+
+ if (quorum_type != NULL) {
+ *quorum_type = local_quorum_type;
+ }
+
+ if (model_data != NULL) {
+ switch (model) {
+ case QUORUM_MODEL_V0:
+ memcpy(&quorum_inst->model_v0_data, model_data, sizeof(quorum_model_v0_data_t));
+ break;
+ case QUORUM_MODEL_V1:
+ memcpy(&quorum_inst->model_v1_data, model_data, sizeof(quorum_model_v1_data_t));
+ break;
+ }
+ }
+
+ quorum_inst->model_data.model = model;
+ quorum_inst->context = context;
+
+ (void)hdb_handle_put (&quorum_handle_t_db, *handle);
+
+ return (error);
+
+error_put_destroy:
+ (void)hdb_handle_put (&quorum_handle_t_db, *handle);
+error_destroy:
+ (void)hdb_handle_destroy (&quorum_handle_t_db, *handle);
+error_no_destroy:
+ return (error);
+}
+
+static void quorum_inst_free (void *inst)
+{
+ struct quorum_inst *quorum_inst = (struct quorum_inst *)inst;
+ qb_ipcc_disconnect(quorum_inst->c);
+}
+
+cs_error_t quorum_finalize (
+ quorum_handle_t handle)
+{
+ struct quorum_inst *quorum_inst;
+ cs_error_t error;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Another thread has already started finalizing
+ */
+ if (quorum_inst->finalize) {
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ quorum_inst->finalize = 1;
+
+ (void)hdb_handle_destroy (&quorum_handle_t_db, handle);
+
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t quorum_getquorate (
+ quorum_handle_t handle,
+ int *quorate)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+ struct iovec iov;
+ struct qb_ipc_request_header req;
+ struct res_lib_quorum_getquorate res_lib_quorum_getquorate;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req.size = sizeof (req);
+ req.id = MESSAGE_REQ_QUORUM_GETQUORATE;
+
+ iov.iov_base = (char *)&req;
+ iov.iov_len = sizeof (req);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ quorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_quorum_getquorate,
+ sizeof (struct res_lib_quorum_getquorate), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_quorum_getquorate.header.error;
+
+ *quorate = res_lib_quorum_getquorate.quorate;
+
+error_exit:
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t quorum_fd_get (
+ quorum_handle_t handle,
+ int *fd)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = qb_to_cs_error(qb_ipcc_fd_get (quorum_inst->c, fd));
+
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (error);
+}
+
+
+cs_error_t quorum_context_get (
+ quorum_handle_t handle,
+ const void **context)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ *context = quorum_inst->context;
+
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t quorum_context_set (
+ quorum_handle_t handle,
+ const void *context)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ quorum_inst->context = context;
+
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+
+cs_error_t quorum_trackstart (
+ quorum_handle_t handle,
+ unsigned int flags )
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+ struct iovec iov;
+ struct req_lib_quorum_trackstart req_lib_quorum_trackstart;
+ struct qb_ipc_response_header res;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_quorum_trackstart.header.size = sizeof (struct req_lib_quorum_trackstart);
+ req_lib_quorum_trackstart.header.id = MESSAGE_REQ_QUORUM_TRACKSTART;
+ req_lib_quorum_trackstart.track_flags = flags;
+
+ iov.iov_base = (char *)&req_lib_quorum_trackstart;
+ iov.iov_len = sizeof (struct req_lib_quorum_trackstart);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ quorum_inst->c,
+ &iov,
+ 1,
+ &res,
+ sizeof (res), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res.error;
+
+error_exit:
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t quorum_trackstop (
+ quorum_handle_t handle)
+{
+ cs_error_t error;
+ struct quorum_inst *quorum_inst;
+ struct iovec iov;
+ struct qb_ipc_request_header req;
+ struct qb_ipc_response_header res;
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle, (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req.size = sizeof (req);
+ req.id = MESSAGE_REQ_QUORUM_TRACKSTOP;
+
+ iov.iov_base = (char *)&req;
+ iov.iov_len = sizeof (req);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ quorum_inst->c,
+ &iov,
+ 1,
+ &res,
+ sizeof (res), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res.error;
+
+error_exit:
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t quorum_dispatch (
+ quorum_handle_t handle,
+ cs_dispatch_flags_t dispatch_types)
+{
+ int timeout = -1;
+ cs_error_t error;
+ int cont = 1; /* always continue do loop except when set to 0 */
+ struct quorum_inst *quorum_inst;
+ struct quorum_inst quorum_inst_copy;
+ struct qb_ipc_response_header *dispatch_data;
+ char dispatch_buf[IPC_DISPATCH_SIZE];
+ struct res_lib_quorum_notification *res_lib_quorum_notification;
+ struct res_lib_quorum_v1_quorum_notification *res_lib_quorum_v1_quorum_notification;
+ struct res_lib_quorum_v1_nodelist_notification *res_lib_quorum_v1_nodelist_notification;
+ struct quorum_ring_id ring_id;
+ mar_uint32_t *joined_list;
+ mar_uint32_t *left_list;
+
+ if (dispatch_types != CS_DISPATCH_ONE &&
+ dispatch_types != CS_DISPATCH_ALL &&
+ dispatch_types != CS_DISPATCH_BLOCKING &&
+ dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) {
+
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&quorum_handle_t_db, handle,
+ (void *)&quorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
+ * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
+ */
+ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ timeout = 0;
+ }
+
+ dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
+ do {
+ error = qb_to_cs_error (qb_ipcc_event_recv (
+ quorum_inst->c,
+ dispatch_buf,
+ IPC_DISPATCH_SIZE,
+ timeout));
+ if (error == CS_ERR_BAD_HANDLE) {
+ error = CS_OK;
+ goto error_put;
+ }
+ if (error == CS_ERR_TRY_AGAIN) {
+ if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ /*
+ * Don't mask error
+ */
+ goto error_put;
+ }
+ error = CS_OK;
+ if (dispatch_types == CS_DISPATCH_ALL) {
+ break; /* exit do while cont is 1 loop */
+ } else {
+ continue; /* next poll */
+ }
+ }
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ /*
+ * Make copy of callbacks, message data, unlock instance, and call callback
+ * A risk of this dispatch method is that the callback routines may
+ * operate at the same time that quorum_finalize has been called in another thread.
+ */
+ memcpy (&quorum_inst_copy, quorum_inst, sizeof(quorum_inst_copy));
+ switch (quorum_inst_copy.model_data.model) {
+ case QUORUM_MODEL_V0:
+ /*
+ * Dispatch incoming message
+ */
+ switch (dispatch_data->id) {
+ case MESSAGE_RES_QUORUM_NOTIFICATION:
+ if (quorum_inst_copy.model_v0_data.quorum_notify_fn == NULL) {
+ break;
+ }
+ res_lib_quorum_notification = (struct res_lib_quorum_notification *)dispatch_data;
+
+ quorum_inst_copy.model_v0_data.quorum_notify_fn ( handle,
+ res_lib_quorum_notification->quorate,
+ res_lib_quorum_notification->ring_seq,
+ res_lib_quorum_notification->view_list_entries,
+ res_lib_quorum_notification->view_list);
+ break;
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_put;
+ break;
+ } /* switch (dispatch_data->id) */
+ break; /* case QUORUM_MODEL_V0 */
+ case QUORUM_MODEL_V1:
+ /*
+ * Dispatch incoming message
+ */
+ switch (dispatch_data->id) {
+ case MESSAGE_RES_QUORUM_V1_QUORUM_NOTIFICATION:
+ if (quorum_inst_copy.model_v1_data.quorum_notify_fn == NULL) {
+ break;
+ }
+ res_lib_quorum_v1_quorum_notification =
+ (struct res_lib_quorum_v1_quorum_notification *)dispatch_data;
+
+ ring_id.nodeid = res_lib_quorum_v1_quorum_notification->ring_id.nodeid;
+ ring_id.seq = res_lib_quorum_v1_quorum_notification->ring_id.seq;
+
+ quorum_inst_copy.model_v1_data.quorum_notify_fn ( handle,
+ res_lib_quorum_v1_quorum_notification->quorate,
+ ring_id,
+ res_lib_quorum_v1_quorum_notification->view_list_entries,
+ res_lib_quorum_v1_quorum_notification->view_list);
+ break;
+ case MESSAGE_RES_QUORUM_V1_NODELIST_NOTIFICATION:
+ if (quorum_inst_copy.model_v1_data.nodelist_notify_fn == NULL) {
+ break;
+ }
+ res_lib_quorum_v1_nodelist_notification =
+ (struct res_lib_quorum_v1_nodelist_notification *)dispatch_data;
+
+ ring_id.nodeid = res_lib_quorum_v1_nodelist_notification->ring_id.nodeid;
+ ring_id.seq = res_lib_quorum_v1_nodelist_notification->ring_id.seq;
+
+ joined_list = res_lib_quorum_v1_nodelist_notification->member_list +
+ res_lib_quorum_v1_nodelist_notification->member_list_entries;
+ left_list = joined_list +
+ res_lib_quorum_v1_nodelist_notification->joined_list_entries;
+
+ quorum_inst_copy.model_v1_data.nodelist_notify_fn ( handle,
+ ring_id,
+ res_lib_quorum_v1_nodelist_notification->member_list_entries,
+ res_lib_quorum_v1_nodelist_notification->member_list,
+ res_lib_quorum_v1_nodelist_notification->joined_list_entries,
+ joined_list,
+ res_lib_quorum_v1_nodelist_notification->left_list_entries,
+ left_list);
+ break;
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_put;
+ break;
+ } /* switch (dispatch_data->id) */
+ break; /* case QUORUM_MODEL_V1 */
+ }
+ if (quorum_inst->finalize) {
+ /*
+ * If the finalize has been called then get out of the dispatch.
+ */
+ error = CS_ERR_BAD_HANDLE;
+ goto error_put;
+ }
+
+ /*
+ * Determine if more messages should be processed
+ */
+ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ cont = 0;
+ }
+ } while (cont);
+
+error_put:
+ (void)hdb_handle_put (&quorum_handle_t_db, handle);
+ return (error);
+}
diff --git a/lib/sam.c b/lib/sam.c
new file mode 100644
index 0000000..94dbf2a
--- /dev/null
+++ b/lib/sam.c
@@ -0,0 +1,1489 @@
+/*
+ * Copyright (c) 2009-2011 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Jan Friesse (jfriesse@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the Red Hat, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Provides a SAM API
+ */
+
+#include <config.h>
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <poll.h>
+
+#include <corosync/corotypes.h>
+#include <qb/qbipcc.h>
+#include <corosync/corodefs.h>
+#include <corosync/cmap.h>
+#include <corosync/hdb.h>
+#include <corosync/quorum.h>
+
+#include <corosync/sam.h>
+
+#include "util.h"
+
+#include <stdio.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define SAM_CMAP_S_FAILED "failed"
+#define SAM_CMAP_S_REGISTERED "stopped"
+#define SAM_CMAP_S_STARTED "running"
+#define SAM_CMAP_S_Q_WAIT "waiting for quorum"
+
+#define SAM_RP_MASK_Q(pol) (pol & (~SAM_RECOVERY_POLICY_QUORUM))
+#define SAM_RP_MASK_C(pol) (pol & (~SAM_RECOVERY_POLICY_CMAP))
+#define SAM_RP_MASK(pol) (pol & (~(SAM_RECOVERY_POLICY_QUORUM | SAM_RECOVERY_POLICY_CMAP)))
+
+enum sam_internal_status_t {
+ SAM_INTERNAL_STATUS_NOT_INITIALIZED = 0,
+ SAM_INTERNAL_STATUS_INITIALIZED,
+ SAM_INTERNAL_STATUS_REGISTERED,
+ SAM_INTERNAL_STATUS_STARTED,
+ SAM_INTERNAL_STATUS_FINALIZED
+};
+
+enum sam_command_t {
+ SAM_COMMAND_START,
+ SAM_COMMAND_STOP,
+ SAM_COMMAND_HB,
+ SAM_COMMAND_DATA_STORE,
+ SAM_COMMAND_WARN_SIGNAL_SET,
+ SAM_COMMAND_MARK_FAILED,
+};
+
+enum sam_reply_t {
+ SAM_REPLY_OK,
+ SAM_REPLY_ERROR,
+};
+
+enum sam_parent_action_t {
+ SAM_PARENT_ACTION_ERROR,
+ SAM_PARENT_ACTION_RECOVERY,
+ SAM_PARENT_ACTION_QUIT,
+ SAM_PARENT_ACTION_CONTINUE
+};
+
+enum sam_cmap_key_t {
+ SAM_CMAP_KEY_RECOVERY,
+ SAM_CMAP_KEY_HC_PERIOD,
+ SAM_CMAP_KEY_LAST_HC,
+ SAM_CMAP_KEY_STATE,
+};
+
+static struct {
+ int time_interval;
+ sam_recovery_policy_t recovery_policy;
+ enum sam_internal_status_t internal_status;
+ unsigned int instance_id;
+ int child_fd_out;
+ int child_fd_in;
+ int term_send;
+ int warn_signal;
+ int am_i_child;
+
+ sam_hc_callback_t hc_callback;
+ pthread_t cb_thread;
+ int cb_rpipe_fd, cb_wpipe_fd;
+ int cb_registered;
+
+ void *user_data;
+ size_t user_data_size;
+ size_t user_data_allocated;
+
+ pthread_mutex_t lock;
+
+ quorum_handle_t quorum_handle;
+ uint32_t quorate;
+ int quorum_fd;
+
+ cmap_handle_t cmap_handle;
+ char cmap_pid_path[CMAP_KEYNAME_MAXLEN];
+} sam_internal_data;
+
+extern const char *__progname;
+
+static cs_error_t sam_cmap_update_key (enum sam_cmap_key_t key, const char *value)
+{
+ cs_error_t err;
+ const char *svalue;
+ uint64_t hc_period, last_hc;
+
+ const char *ssvalue[] = { [SAM_RECOVERY_POLICY_QUIT] = "quit", [SAM_RECOVERY_POLICY_RESTART] = "restart" };
+ char key_name[CMAP_KEYNAME_MAXLEN];
+
+ switch (key) {
+ case SAM_CMAP_KEY_RECOVERY:
+ svalue = ssvalue[SAM_RP_MASK (sam_internal_data.recovery_policy)];
+
+ if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
+ "recovery") >= CMAP_KEYNAME_MAXLEN) {
+
+ err = CS_ERR_NAME_TOO_LONG;
+ goto exit_error;
+ }
+
+ if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) {
+ goto exit_error;
+ }
+ break;
+ case SAM_CMAP_KEY_HC_PERIOD:
+ hc_period = sam_internal_data.time_interval;
+
+ if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
+ "poll_period") >= CMAP_KEYNAME_MAXLEN) {
+
+ err = CS_ERR_NAME_TOO_LONG;
+ goto exit_error;
+ }
+
+ if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, hc_period)) != CS_OK) {
+ goto exit_error;
+ }
+ break;
+ case SAM_CMAP_KEY_LAST_HC:
+ last_hc = cs_timestamp_get();
+
+ if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
+ "last_updated") >= CMAP_KEYNAME_MAXLEN) {
+
+ err = CS_ERR_NAME_TOO_LONG;
+ goto exit_error;
+ }
+ if ((err = cmap_set_uint64(sam_internal_data.cmap_handle, key_name, last_hc)) != CS_OK) {
+ goto exit_error;
+ }
+ break;
+ case SAM_CMAP_KEY_STATE:
+ svalue = value;
+ if (snprintf(key_name, CMAP_KEYNAME_MAXLEN, "%s%s", sam_internal_data.cmap_pid_path,
+ "state") >= CMAP_KEYNAME_MAXLEN) {
+
+ err = CS_ERR_NAME_TOO_LONG;
+ goto exit_error;
+ }
+
+ if ((err = cmap_set_string(sam_internal_data.cmap_handle, key_name, svalue)) != CS_OK) {
+ goto exit_error;
+ }
+ break;
+ }
+
+ return (CS_OK);
+
+exit_error:
+ return (err);
+}
+
+static cs_error_t sam_cmap_destroy_pid_path (void)
+{
+ cmap_iter_handle_t iter;
+ cs_error_t err;
+ char key_name[CMAP_KEYNAME_MAXLEN + 1];
+
+ err = cmap_iter_init(sam_internal_data.cmap_handle, sam_internal_data.cmap_pid_path, &iter);
+ if (err != CS_OK) {
+ goto error_exit;
+ }
+
+ while ((err = cmap_iter_next(sam_internal_data.cmap_handle, iter, key_name, NULL, NULL)) == CS_OK) {
+ cmap_delete(sam_internal_data.cmap_handle, key_name);
+ }
+
+ err = cmap_iter_finalize(sam_internal_data.cmap_handle, iter);
+
+error_exit:
+ return (err);
+}
+
+static cs_error_t sam_cmap_register (void)
+{
+ cs_error_t err;
+ cmap_handle_t cmap_handle;
+
+ if ((err = cmap_initialize (&cmap_handle)) != CS_OK) {
+ return (err);
+ }
+
+ snprintf(sam_internal_data.cmap_pid_path, CMAP_KEYNAME_MAXLEN, "resources.process.%d.", getpid());
+
+ sam_internal_data.cmap_handle = cmap_handle;
+
+ if ((err = sam_cmap_update_key (SAM_CMAP_KEY_RECOVERY, NULL)) != CS_OK) {
+ goto destroy_finalize_error;
+ }
+
+ if ((err = sam_cmap_update_key (SAM_CMAP_KEY_HC_PERIOD, NULL)) != CS_OK) {
+ goto destroy_finalize_error;
+ }
+
+ return (CS_OK);
+
+destroy_finalize_error:
+ sam_cmap_destroy_pid_path ();
+ cmap_finalize (cmap_handle);
+ return (err);
+}
+
+static void quorum_notification_fn (
+ quorum_handle_t handle,
+ uint32_t quorate,
+ uint64_t ring_id,
+ uint32_t view_list_entries,
+ uint32_t *view_list)
+{
+ sam_internal_data.quorate = quorate;
+}
+
+cs_error_t sam_initialize (
+ int time_interval,
+ sam_recovery_policy_t recovery_policy)
+{
+ quorum_callbacks_t quorum_callbacks;
+ uint32_t quorum_type;
+ cs_error_t err;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_NOT_INITIALIZED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ if (SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_QUIT &&
+ SAM_RP_MASK (recovery_policy) != SAM_RECOVERY_POLICY_RESTART) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (recovery_policy & SAM_RECOVERY_POLICY_QUORUM) {
+ /*
+ * Initialize quorum
+ */
+ quorum_callbacks.quorum_notify_fn = quorum_notification_fn;
+ if ((err = quorum_initialize (&sam_internal_data.quorum_handle, &quorum_callbacks, &quorum_type)) != CS_OK) {
+ goto exit_error;
+ }
+
+ if ((err = quorum_trackstart (sam_internal_data.quorum_handle, CS_TRACK_CHANGES)) != CS_OK) {
+ goto exit_error_quorum;
+ }
+
+ if ((err = quorum_fd_get (sam_internal_data.quorum_handle, &sam_internal_data.quorum_fd)) != CS_OK) {
+ goto exit_error_quorum;
+ }
+
+ /*
+ * Dispatch initial quorate state
+ */
+ if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
+ goto exit_error_quorum;
+ }
+ }
+ sam_internal_data.recovery_policy = recovery_policy;
+
+ sam_internal_data.time_interval = time_interval;
+
+ sam_internal_data.internal_status = SAM_INTERNAL_STATUS_INITIALIZED;
+
+ sam_internal_data.warn_signal = SIGTERM;
+
+ sam_internal_data.am_i_child = 0;
+
+ sam_internal_data.user_data = NULL;
+ sam_internal_data.user_data_size = 0;
+ sam_internal_data.user_data_allocated = 0;
+
+ pthread_mutex_init (&sam_internal_data.lock, NULL);
+
+ return (CS_OK);
+
+exit_error_quorum:
+ quorum_finalize (sam_internal_data.quorum_handle);
+exit_error:
+ return (err);
+}
+
+/*
+ * Wrapper on top of write(2) function. It handles EAGAIN and EINTR states and sends whole buffer if possible.
+ */
+static size_t sam_safe_write (
+ int d,
+ const void *buf,
+ size_t nbyte)
+{
+ ssize_t bytes_write;
+ ssize_t tmp_bytes_write;
+
+ bytes_write = 0;
+
+ do {
+ tmp_bytes_write = write (d, (const char *)buf + bytes_write,
+ (nbyte - bytes_write > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_write);
+
+ if (tmp_bytes_write == -1) {
+ if (!(errno == EAGAIN || errno == EINTR))
+ return -1;
+ } else {
+ bytes_write += tmp_bytes_write;
+ }
+ } while (bytes_write != nbyte);
+
+ return (bytes_write);
+}
+
+/*
+ * Wrapper on top of read(2) function. It handles EAGAIN and EINTR states and reads whole buffer if possible.
+ */
+static size_t sam_safe_read (
+ int d,
+ void *buf,
+ size_t nbyte)
+{
+ ssize_t bytes_read;
+ ssize_t tmp_bytes_read;
+
+ bytes_read = 0;
+
+ do {
+ tmp_bytes_read = read (d, (char *)buf + bytes_read,
+ (nbyte - bytes_read > SSIZE_MAX) ? SSIZE_MAX : nbyte - bytes_read);
+
+ if (tmp_bytes_read == -1) {
+ if (!(errno == EAGAIN || errno == EINTR))
+ return -1;
+ } else {
+ bytes_read += tmp_bytes_read;
+ }
+
+ } while (bytes_read != nbyte && tmp_bytes_read != 0);
+
+ return (bytes_read);
+}
+
+static cs_error_t sam_read_reply (
+ int child_fd_in)
+{
+ char reply;
+ cs_error_t err;
+
+ if (sam_safe_read (sam_internal_data.child_fd_in, &reply, sizeof (reply)) != sizeof (reply)) {
+ return (CS_ERR_LIBRARY);
+ }
+
+ switch (reply) {
+ case SAM_REPLY_ERROR:
+ /*
+ * Read error and return that
+ */
+ if (sam_safe_read (sam_internal_data.child_fd_in, &err, sizeof (err)) != sizeof (err)) {
+ return (CS_ERR_LIBRARY);
+ }
+
+ return (err);
+ break;
+ case SAM_REPLY_OK:
+ /*
+ * Everything correct
+ */
+ break;
+ default:
+ return (CS_ERR_LIBRARY);
+ break;
+ }
+
+ return (CS_OK);
+}
+
+cs_error_t sam_data_getsize (size_t *size)
+{
+ if (size == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ pthread_mutex_lock (&sam_internal_data.lock);
+
+ *size = sam_internal_data.user_data_size;
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (CS_OK);
+}
+
+cs_error_t sam_data_restore (
+ void *data,
+ size_t size)
+{
+ cs_error_t err;
+
+ err = CS_OK;
+
+ if (data == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ pthread_mutex_lock (&sam_internal_data.lock);
+
+ if (sam_internal_data.user_data_size == 0) {
+ err = CS_OK;
+
+ goto error_unlock;
+ }
+
+ if (size < sam_internal_data.user_data_size) {
+ err = CS_ERR_INVALID_PARAM;
+
+ goto error_unlock;
+ }
+
+ memcpy (data, sam_internal_data.user_data, sam_internal_data.user_data_size);
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (CS_OK);
+
+error_unlock:
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (err);
+}
+
+cs_error_t sam_data_store (
+ const void *data,
+ size_t size)
+{
+ cs_error_t err;
+ char command;
+ char *new_data;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+
+ if (data == NULL) {
+ size = 0;
+ }
+
+ pthread_mutex_lock (&sam_internal_data.lock);
+
+ if (sam_internal_data.am_i_child) {
+ /*
+ * We are child so we must send data to parent
+ */
+ command = SAM_COMMAND_DATA_STORE;
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
+ err = CS_ERR_LIBRARY;
+
+ goto error_unlock;
+ }
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &size, sizeof (size)) != sizeof (size)) {
+ err = CS_ERR_LIBRARY;
+
+ goto error_unlock;
+ }
+
+ if (data != NULL && sam_safe_write (sam_internal_data.child_fd_out, data, size) != size) {
+ err = CS_ERR_LIBRARY;
+
+ goto error_unlock;
+ }
+
+ /*
+ * And wait for reply
+ */
+ if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
+ goto error_unlock;
+ }
+ }
+
+ /*
+ * We are parent or we received OK reply from parent -> do required action
+ */
+ if (data == NULL) {
+ free (sam_internal_data.user_data);
+ sam_internal_data.user_data = NULL;
+ sam_internal_data.user_data_allocated = 0;
+ sam_internal_data.user_data_size = 0;
+ } else {
+ if (sam_internal_data.user_data_allocated < size) {
+ if ((new_data = realloc (sam_internal_data.user_data, size)) == NULL) {
+ err = CS_ERR_NO_MEMORY;
+
+ goto error_unlock;
+ }
+
+ sam_internal_data.user_data_allocated = size;
+ } else {
+ new_data = sam_internal_data.user_data;
+ }
+ sam_internal_data.user_data = new_data;
+ sam_internal_data.user_data_size = size;
+
+ memcpy (sam_internal_data.user_data, data, size);
+ }
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (CS_OK);
+
+error_unlock:
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (err);
+}
+
+cs_error_t sam_start (void)
+{
+ char command;
+ cs_error_t err;
+ sam_recovery_policy_t recpol;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ recpol = sam_internal_data.recovery_policy;
+
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) {
+ pthread_mutex_lock (&sam_internal_data.lock);
+ }
+
+ command = SAM_COMMAND_START;
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) {
+ pthread_mutex_unlock (&sam_internal_data.lock);
+ }
+
+ return (CS_ERR_LIBRARY);
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM || recpol & SAM_RECOVERY_POLICY_CMAP) {
+ /*
+ * Wait for parent reply
+ */
+ if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (err);
+ }
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+ }
+
+ if (sam_internal_data.hc_callback)
+ if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command))
+ return (CS_ERR_LIBRARY);
+
+ sam_internal_data.internal_status = SAM_INTERNAL_STATUS_STARTED;
+
+ return (CS_OK);
+}
+
+cs_error_t sam_stop (void)
+{
+ char command;
+ cs_error_t err;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ command = SAM_COMMAND_STOP;
+
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ pthread_mutex_lock (&sam_internal_data.lock);
+ }
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ pthread_mutex_unlock (&sam_internal_data.lock);
+ }
+
+ return (CS_ERR_LIBRARY);
+ }
+
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ /*
+ * Wait for parent reply
+ */
+ if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (err);
+ }
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+ }
+
+ if (sam_internal_data.hc_callback)
+ if (sam_safe_write (sam_internal_data.cb_wpipe_fd, &command, sizeof (command)) != sizeof (command))
+ return (CS_ERR_LIBRARY);
+
+ sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
+
+ return (CS_OK);
+}
+
+cs_error_t sam_hc_send (void)
+{
+ char command;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ command = SAM_COMMAND_HB;
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command))
+ return (CS_ERR_LIBRARY);
+
+ return (CS_OK);
+}
+
+cs_error_t sam_finalize (void)
+{
+ cs_error_t error;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ if (sam_internal_data.internal_status == SAM_INTERNAL_STATUS_STARTED) {
+ error = sam_stop ();
+ if (error != CS_OK)
+ goto exit_error;
+ }
+
+ sam_internal_data.internal_status = SAM_INTERNAL_STATUS_FINALIZED;
+
+ free (sam_internal_data.user_data);
+
+exit_error:
+ return (CS_OK);
+}
+
+cs_error_t sam_mark_failed (void)
+{
+ char command;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ if (!(sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP)) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ command = SAM_COMMAND_MARK_FAILED;
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command))
+ return (CS_ERR_LIBRARY);
+
+ return (CS_OK);
+}
+
+cs_error_t sam_warn_signal_set (int warn_signal)
+{
+ char command;
+ cs_error_t err;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED &&
+ sam_internal_data.internal_status != SAM_INTERNAL_STATUS_STARTED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ pthread_mutex_lock (&sam_internal_data.lock);
+
+ if (sam_internal_data.am_i_child) {
+ /*
+ * We are child so we must send data to parent
+ */
+ command = SAM_COMMAND_WARN_SIGNAL_SET;
+ if (sam_safe_write (sam_internal_data.child_fd_out, &command, sizeof (command)) != sizeof (command)) {
+ err = CS_ERR_LIBRARY;
+
+ goto error_unlock;
+ }
+
+ if (sam_safe_write (sam_internal_data.child_fd_out, &warn_signal, sizeof (warn_signal)) !=
+ sizeof (warn_signal)) {
+ err = CS_ERR_LIBRARY;
+
+ goto error_unlock;
+ }
+
+ /*
+ * And wait for reply
+ */
+ if ((err = sam_read_reply (sam_internal_data.child_fd_in)) != CS_OK) {
+ goto error_unlock;
+ }
+ }
+
+ /*
+ * We are parent or we received OK reply from parent -> do required action
+ */
+ sam_internal_data.warn_signal = warn_signal;
+
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (CS_OK);
+
+error_unlock:
+ pthread_mutex_unlock (&sam_internal_data.lock);
+
+ return (err);
+}
+
+static cs_error_t sam_parent_reply_send (
+ cs_error_t err,
+ int parent_fd_in,
+ int parent_fd_out)
+{
+ char reply;
+
+ if (err == CS_OK) {
+ reply = SAM_REPLY_OK;
+
+ if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
+ err = CS_ERR_LIBRARY;
+ goto error_reply;
+ }
+
+ return (CS_OK);
+ }
+
+error_reply:
+ reply = SAM_REPLY_ERROR;
+ if (sam_safe_write (parent_fd_out, &reply, sizeof (reply)) != sizeof (reply)) {
+ return (CS_ERR_LIBRARY);
+ }
+ if (sam_safe_write (parent_fd_out, &err, sizeof (err)) != sizeof (err)) {
+ return (CS_ERR_LIBRARY);
+ }
+
+ return (err);
+}
+
+
+static cs_error_t sam_parent_warn_signal_set (
+ int parent_fd_in,
+ int parent_fd_out)
+{
+ int warn_signal;
+ cs_error_t err;
+
+ err = CS_OK;
+
+ if (sam_safe_read (parent_fd_in, &warn_signal, sizeof (warn_signal)) != sizeof (warn_signal)) {
+ err = CS_ERR_LIBRARY;
+ goto error_reply;
+ }
+
+ err = sam_warn_signal_set (warn_signal);
+ if (err != CS_OK) {
+ goto error_reply;
+ }
+
+
+ return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
+
+error_reply:
+ return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
+}
+
+static cs_error_t sam_parent_wait_for_quorum (
+ int parent_fd_in,
+ int parent_fd_out)
+{
+ cs_error_t err;
+ struct pollfd pfds[2];
+ int poll_err;
+
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_Q_WAIT)) != CS_OK) {
+ goto error_reply;
+ }
+ }
+
+ /*
+ * Update current quorum
+ */
+ if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL)) != CS_OK) {
+ goto error_reply;
+ }
+
+ /*
+ * Wait for quorum
+ */
+ while (!sam_internal_data.quorate) {
+ pfds[0].fd = parent_fd_in;
+ pfds[0].events = 0;
+ pfds[0].revents = 0;
+
+ pfds[1].fd = sam_internal_data.quorum_fd;
+ pfds[1].events = POLLIN;
+ pfds[1].revents = 0;
+
+ poll_err = poll (pfds, 2, -1);
+
+ if (poll_err == -1) {
+ /*
+ * Error in poll
+ * If it is EINTR, continue, otherwise QUIT
+ */
+ if (errno != EINTR) {
+ err = CS_ERR_LIBRARY;
+ goto error_reply;
+ }
+ }
+
+ if (pfds[0].revents != 0) {
+ if (pfds[0].revents == POLLERR || pfds[0].revents == POLLHUP ||pfds[0].revents == POLLNVAL) {
+ /*
+ * Child has exited
+ */
+ return (CS_OK);
+ }
+ }
+
+ if (pfds[1].revents != 0) {
+ if ((err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ONE)) != CS_OK) {
+ goto error_reply;
+ }
+ }
+ }
+
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_STARTED)) != CS_OK) {
+ goto error_reply;
+ }
+ }
+
+ return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
+
+error_reply:
+ if (sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_CMAP) {
+ sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED);
+ }
+
+ return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
+}
+
+static cs_error_t sam_parent_cmap_state_set (
+ int parent_fd_in,
+ int parent_fd_out,
+ int state)
+{
+ cs_error_t err;
+ const char *state_s;
+
+ if (state == 1) {
+ state_s = SAM_CMAP_S_STARTED;
+ } else {
+ state_s = SAM_CMAP_S_REGISTERED;
+ }
+
+ if ((err = sam_cmap_update_key (SAM_CMAP_KEY_STATE, state_s)) != CS_OK) {
+ goto error_reply;
+ }
+
+ return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
+
+error_reply:
+ return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
+}
+
+static cs_error_t sam_parent_kill_child (
+ int *action,
+ pid_t child_pid)
+{
+ /*
+ * Kill child process
+ */
+ if (!sam_internal_data.term_send) {
+ /*
+ * We didn't send warn_signal yet.
+ */
+ kill (child_pid, sam_internal_data.warn_signal);
+
+ sam_internal_data.term_send = 1;
+ } else {
+ /*
+ * We sent child warning. Now, we will not be so nice
+ */
+ kill (child_pid, SIGKILL);
+ *action = SAM_PARENT_ACTION_RECOVERY;
+ }
+
+ return (CS_OK);
+}
+
+static cs_error_t sam_parent_mark_child_failed (
+ int *action,
+ pid_t child_pid)
+{
+ sam_recovery_policy_t recpol;
+
+ recpol = sam_internal_data.recovery_policy;
+
+ sam_internal_data.term_send = 1;
+ sam_internal_data.recovery_policy = SAM_RECOVERY_POLICY_QUIT |
+ (SAM_RP_MASK_C (recpol) ? SAM_RECOVERY_POLICY_CMAP : 0) |
+ (SAM_RP_MASK_Q (recpol) ? SAM_RECOVERY_POLICY_QUORUM : 0);
+
+ return (sam_parent_kill_child (action, child_pid));
+}
+
+static cs_error_t sam_parent_data_store (
+ int parent_fd_in,
+ int parent_fd_out)
+{
+ char *user_data;
+ ssize_t size;
+ cs_error_t err;
+
+ err = CS_OK;
+ user_data = NULL;
+
+ if (sam_safe_read (parent_fd_in, &size, sizeof (size)) != sizeof (size)) {
+ err = CS_ERR_LIBRARY;
+ goto error_reply;
+ }
+
+ if (size > 0) {
+ user_data = malloc (size);
+ if (user_data == NULL) {
+ err = CS_ERR_NO_MEMORY;
+ goto error_reply;
+ }
+
+ if (sam_safe_read (parent_fd_in, user_data, size) != size) {
+ err = CS_ERR_LIBRARY;
+ goto free_error_reply;
+ }
+ }
+
+ err = sam_data_store (user_data, size);
+ if (err != CS_OK) {
+ goto free_error_reply;
+ }
+
+ free (user_data);
+
+ return (sam_parent_reply_send (CS_OK, parent_fd_in, parent_fd_out));
+
+free_error_reply:
+ free (user_data);
+error_reply:
+ return (sam_parent_reply_send (err, parent_fd_in, parent_fd_out));
+}
+
+static enum sam_parent_action_t sam_parent_handler (
+ int parent_fd_in,
+ int parent_fd_out,
+ pid_t child_pid)
+{
+ int poll_error;
+ int action;
+ int status;
+ ssize_t bytes_read;
+ char command;
+ int time_interval;
+ struct pollfd pfds[2];
+ nfds_t nfds;
+ cs_error_t err;
+ sam_recovery_policy_t recpol;
+
+ status = 0;
+
+ action = SAM_PARENT_ACTION_CONTINUE;
+ recpol = sam_internal_data.recovery_policy;
+
+ while (action == SAM_PARENT_ACTION_CONTINUE) {
+ pfds[0].fd = parent_fd_in;
+ pfds[0].events = POLLIN;
+ pfds[0].revents = 0;
+ nfds = 1;
+
+ if (status == 1 && sam_internal_data.time_interval != 0) {
+ time_interval = sam_internal_data.time_interval;
+ } else {
+ time_interval = -1;
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
+ pfds[nfds].fd = sam_internal_data.quorum_fd;
+ pfds[nfds].events = POLLIN;
+ pfds[nfds].revents = 0;
+ nfds++;
+ }
+
+ poll_error = poll (pfds, nfds, time_interval);
+
+ if (poll_error == -1) {
+ /*
+ * Error in poll
+ * If it is EINTR, continue, otherwise QUIT
+ */
+ if (errno != EINTR) {
+ action = SAM_PARENT_ACTION_ERROR;
+ }
+ }
+
+ if (poll_error == 0) {
+ /*
+ * Time limit expires
+ */
+ if (status == 0) {
+ action = SAM_PARENT_ACTION_QUIT;
+ } else {
+ sam_parent_kill_child (&action, child_pid);
+ }
+ }
+
+ if (poll_error > 0) {
+ if (pfds[0].revents != 0) {
+ /*
+ * We have EOF or command in pipe
+ */
+ bytes_read = sam_safe_read (parent_fd_in, &command, 1);
+
+ if (bytes_read == 0) {
+ /*
+ * Handle EOF -> Take recovery action or quit if sam_start wasn't called
+ */
+ if (status == 0)
+ action = SAM_PARENT_ACTION_QUIT;
+ else
+ action = SAM_PARENT_ACTION_RECOVERY;
+
+ continue;
+ }
+
+ if (bytes_read == -1) {
+ action = SAM_PARENT_ACTION_ERROR;
+ goto action_exit;
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ sam_cmap_update_key (SAM_CMAP_KEY_LAST_HC, NULL);
+ }
+
+ /*
+ * We have read command
+ */
+ switch (command) {
+ case SAM_COMMAND_START:
+ if (status == 0) {
+ /*
+ * Not started yet
+ */
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
+ if (sam_parent_wait_for_quorum (parent_fd_in,
+ parent_fd_out) != CS_OK) {
+ continue;
+ }
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ if (sam_parent_cmap_state_set (parent_fd_in,
+ parent_fd_out, 1) != CS_OK) {
+ continue;
+ }
+ }
+
+ status = 1;
+ }
+ break;
+ case SAM_COMMAND_STOP:
+ if (status == 1) {
+ /*
+ * Started
+ */
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ if (sam_parent_cmap_state_set (parent_fd_in,
+ parent_fd_out, 0) != CS_OK) {
+ continue;
+ }
+ }
+
+ status = 0;
+ }
+ break;
+ case SAM_COMMAND_DATA_STORE:
+ sam_parent_data_store (parent_fd_in, parent_fd_out);
+ break;
+ case SAM_COMMAND_WARN_SIGNAL_SET:
+ sam_parent_warn_signal_set (parent_fd_in, parent_fd_out);
+ break;
+ case SAM_COMMAND_MARK_FAILED:
+ status = 1;
+ sam_parent_mark_child_failed (&action, child_pid);
+ break;
+ }
+ } /* if (pfds[0].revents != 0) */
+
+ if ((sam_internal_data.recovery_policy & SAM_RECOVERY_POLICY_QUORUM) &&
+ pfds[1].revents != 0) {
+ /*
+ * Handle quorum change
+ */
+ err = quorum_dispatch (sam_internal_data.quorum_handle, CS_DISPATCH_ALL);
+
+ if (status == 1 &&
+ (!sam_internal_data.quorate || (err != CS_ERR_TRY_AGAIN && err != CS_OK))) {
+ sam_parent_kill_child (&action, child_pid);
+ }
+ }
+ } /* select_error > 0 */
+ } /* action == SAM_PARENT_ACTION_CONTINUE */
+
+action_exit:
+ return action;
+}
+
+cs_error_t sam_register (
+ unsigned int *instance_id)
+{
+ cs_error_t error;
+ pid_t pid;
+ int pipe_error;
+ int pipe_fd_out[2], pipe_fd_in[2];
+ enum sam_parent_action_t action, old_action;
+ int child_status;
+ sam_recovery_policy_t recpol;
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_INITIALIZED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ recpol = sam_internal_data.recovery_policy;
+
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ /*
+ * Register to cmap
+ */
+ if ((error = sam_cmap_register ()) != CS_OK) {
+ goto error_exit;
+ }
+ }
+
+ error = CS_OK;
+
+ while (1) {
+ if ((pipe_error = pipe (pipe_fd_out)) != 0) {
+ error = CS_ERR_LIBRARY;
+ goto error_exit;
+ }
+
+ if ((pipe_error = pipe (pipe_fd_in)) != 0) {
+ close (pipe_fd_out[0]);
+ close (pipe_fd_out[1]);
+
+ error = CS_ERR_LIBRARY;
+ goto error_exit;
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ if ((error = sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_REGISTERED)) != CS_OK) {
+ goto error_exit;
+ }
+ }
+
+ sam_internal_data.instance_id++;
+
+ sam_internal_data.term_send = 0;
+
+ pid = fork ();
+
+ if (pid == -1) {
+ /*
+ * Fork error
+ */
+ sam_internal_data.instance_id--;
+
+ error = CS_ERR_LIBRARY;
+ goto error_exit;
+ }
+
+ if (pid == 0) {
+ /*
+ * Child process
+ */
+ close (pipe_fd_out[0]);
+ close (pipe_fd_in[1]);
+
+ sam_internal_data.child_fd_out = pipe_fd_out[1];
+ sam_internal_data.child_fd_in = pipe_fd_in[0];
+
+ if (instance_id)
+ *instance_id = sam_internal_data.instance_id;
+
+ sam_internal_data.am_i_child = 1;
+ sam_internal_data.internal_status = SAM_INTERNAL_STATUS_REGISTERED;
+
+ pthread_mutex_init (&sam_internal_data.lock, NULL);
+
+ goto error_exit;
+ } else {
+ /*
+ * Parent process
+ */
+ close (pipe_fd_out[1]);
+ close (pipe_fd_in[0]);
+
+ action = sam_parent_handler (pipe_fd_out[0], pipe_fd_in[1], pid);
+
+ close (pipe_fd_out[0]);
+ close (pipe_fd_in[1]);
+
+ if (action == SAM_PARENT_ACTION_ERROR) {
+ error = CS_ERR_LIBRARY;
+ goto error_exit;
+ }
+
+ /*
+ * We really don't like zombies
+ */
+ while (waitpid (pid, &child_status, 0) == -1 && errno == EINTR)
+ ;
+
+ old_action = action;
+
+ if (action == SAM_PARENT_ACTION_RECOVERY) {
+ if (SAM_RP_MASK (sam_internal_data.recovery_policy) == SAM_RECOVERY_POLICY_QUIT)
+ action = SAM_PARENT_ACTION_QUIT;
+ }
+
+
+ if (action == SAM_PARENT_ACTION_QUIT) {
+ if (recpol & SAM_RECOVERY_POLICY_QUORUM) {
+ quorum_finalize (sam_internal_data.quorum_handle);
+ }
+
+ if (recpol & SAM_RECOVERY_POLICY_CMAP) {
+ if (old_action == SAM_PARENT_ACTION_RECOVERY) {
+ /*
+ * Mark as failed
+ */
+ sam_cmap_update_key (SAM_CMAP_KEY_STATE, SAM_CMAP_S_FAILED);
+ } else {
+ sam_cmap_destroy_pid_path ();
+ }
+ }
+
+ exit (WEXITSTATUS (child_status));
+ }
+
+
+ }
+ }
+
+error_exit:
+ return (error);
+}
+
+static void *hc_callback_thread (void *unused_param)
+{
+ int poll_error;
+ int status;
+ ssize_t bytes_readed;
+ char command;
+ int time_interval, tmp_time_interval;
+ int counter;
+ struct pollfd pfds;
+
+ status = 0;
+ counter = 0;
+
+ time_interval = sam_internal_data.time_interval >> 2;
+
+ while (1) {
+ pfds.fd = sam_internal_data.cb_rpipe_fd;
+ pfds.events = POLLIN;
+ pfds.revents = 0;
+
+ if (status == 1) {
+ tmp_time_interval = time_interval;
+ } else {
+ tmp_time_interval = -1;
+ }
+
+ poll_error = poll (&pfds, 1, tmp_time_interval);
+
+ if (poll_error == 0) {
+ if (sam_hc_send () == CS_OK) {
+ counter++;
+ }
+
+ if (counter >= 4) {
+ if (sam_internal_data.hc_callback () != 0) {
+ status = 3;
+ }
+
+ counter = 0;
+ }
+ }
+
+ if (poll_error > 0) {
+ bytes_readed = sam_safe_read (sam_internal_data.cb_rpipe_fd, &command, 1);
+
+ if (bytes_readed > 0) {
+ if (status == 0 && command == SAM_COMMAND_START)
+ status = 1;
+
+ if (status == 1 && command == SAM_COMMAND_STOP)
+ status = 0;
+
+ }
+ }
+ }
+
+ /*
+ * This makes compiler happy, it's same as return (NULL);
+ */
+ return (unused_param);
+}
+
+cs_error_t sam_hc_callback_register (sam_hc_callback_t cb)
+{
+ cs_error_t error = CS_OK;
+ pthread_attr_t thread_attr;
+ int pipe_error;
+ int pipe_fd[2];
+
+ if (sam_internal_data.internal_status != SAM_INTERNAL_STATUS_REGISTERED) {
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ if (sam_internal_data.time_interval == 0) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ if (sam_internal_data.cb_registered) {
+ sam_internal_data.hc_callback = cb;
+
+ return (CS_OK);
+ }
+
+ /*
+ * We know, this is first registration
+ */
+
+ if (cb == NULL) {
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ pipe_error = pipe (pipe_fd);
+
+ if (pipe_error != 0) {
+ /*
+ * Pipe creation error
+ */
+ error = CS_ERR_LIBRARY;
+ goto error_exit;
+ }
+
+ sam_internal_data.cb_rpipe_fd = pipe_fd[0];
+ sam_internal_data.cb_wpipe_fd = pipe_fd[1];
+
+ /*
+ * Create thread attributes
+ */
+ error = pthread_attr_init (&thread_attr);
+ if (error != 0) {
+ error = CS_ERR_LIBRARY;
+ goto error_close_fd_exit;
+ }
+
+
+ pthread_attr_setdetachstate (&thread_attr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize (&thread_attr, 32768);
+
+ /*
+ * Create thread
+ */
+ error = pthread_create (&sam_internal_data.cb_thread, &thread_attr, hc_callback_thread, NULL);
+
+ if (error != 0) {
+ error = CS_ERR_LIBRARY;
+ goto error_attr_destroy_exit;
+ }
+
+ /*
+ * Cleanup
+ */
+ pthread_attr_destroy(&thread_attr);
+
+ sam_internal_data.cb_registered = 1;
+ sam_internal_data.hc_callback = cb;
+
+ return (CS_OK);
+
+error_attr_destroy_exit:
+ pthread_attr_destroy(&thread_attr);
+error_close_fd_exit:
+ sam_internal_data.cb_rpipe_fd = sam_internal_data.cb_wpipe_fd = 0;
+ close (pipe_fd[0]);
+ close (pipe_fd[1]);
+error_exit:
+ return (error);
+}
diff --git a/lib/util.h b/lib/util.h
new file mode 100644
index 0000000..a1610a7
--- /dev/null
+++ b/lib/util.h
@@ -0,0 +1,54 @@
+
+/*
+ * Copyright (c) 2002-2003 MontaVista Software, Inc.
+ * Copyright (c) 2012 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Steven Dake (sdake@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef COROSYNC_UTIL_H_DEFINED
+#define COROSYNC_UTIL_H_DEFINED
+
+#include <corosync/corotypes.h>
+
+cs_error_t hdb_error_to_cs (int res);
+
+#ifdef HAVE_SMALL_MEMORY_FOOTPRINT
+#define IPC_REQUEST_SIZE 1024*64
+#define IPC_RESPONSE_SIZE 1024*64
+#define IPC_DISPATCH_SIZE 1024*64
+#else
+#define IPC_REQUEST_SIZE 8192*128
+#define IPC_RESPONSE_SIZE 8192*128
+#define IPC_DISPATCH_SIZE 8192*128
+#endif /* HAVE_SMALL_MEMORY_FOOTPRINT */
+
+#endif /* COROSYNC_UTIL_H_DEFINED */
diff --git a/lib/votequorum.c b/lib/votequorum.c
new file mode 100644
index 0000000..4bcac22
--- /dev/null
+++ b/lib/votequorum.c
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2009-2012 Red Hat, Inc.
+ *
+ * All rights reserved.
+ *
+ * Author: Christine Caulfield (ccaulfie@redhat.com)
+ *
+ * This software licensed under BSD license, the text of which follows:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * - Neither the name of the MontaVista Software, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Provides a quorum API using the corosync executive
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <errno.h>
+
+#include <qb/qbdefs.h>
+#include <qb/qbipcc.h>
+
+#include <corosync/corotypes.h>
+#include <corosync/corodefs.h>
+#include <corosync/hdb.h>
+
+#include <corosync/votequorum.h>
+#include <corosync/ipc_votequorum.h>
+
+#include "util.h"
+
+struct votequorum_inst {
+ qb_ipcc_connection_t *c;
+ int finalize;
+ void *context;
+ votequorum_callbacks_t callbacks;
+};
+
+static void votequorum_inst_free (void *inst);
+
+DECLARE_HDB_DATABASE(votequorum_handle_t_db, votequorum_inst_free);
+
+cs_error_t votequorum_initialize (
+ votequorum_handle_t *handle,
+ votequorum_callbacks_t *callbacks)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_create (&votequorum_handle_t_db, sizeof (struct votequorum_inst), handle));
+ if (error != CS_OK) {
+ goto error_no_destroy;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, *handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ goto error_destroy;
+ }
+
+ votequorum_inst->finalize = 0;
+ votequorum_inst->c = qb_ipcc_connect ("votequorum", IPC_REQUEST_SIZE);
+ if (votequorum_inst->c == NULL) {
+ error = qb_to_cs_error(-errno);
+ goto error_put_destroy;
+ }
+
+ if (callbacks)
+ memcpy(&votequorum_inst->callbacks, callbacks, sizeof (*callbacks));
+ else
+ memset(&votequorum_inst->callbacks, 0, sizeof (*callbacks));
+
+ hdb_handle_put (&votequorum_handle_t_db, *handle);
+
+ return (CS_OK);
+
+error_put_destroy:
+ hdb_handle_put (&votequorum_handle_t_db, *handle);
+error_destroy:
+ hdb_handle_destroy (&votequorum_handle_t_db, *handle);
+error_no_destroy:
+ return (error);
+}
+
+static void votequorum_inst_free (void *inst)
+{
+ struct votequorum_inst *vq_inst = (struct votequorum_inst *)inst;
+ qb_ipcc_disconnect(vq_inst->c);
+}
+
+cs_error_t votequorum_finalize (
+ votequorum_handle_t handle)
+{
+ struct votequorum_inst *votequorum_inst;
+ cs_error_t error;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Another thread has already started finalizing
+ */
+ if (votequorum_inst->finalize) {
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+ return (CS_ERR_BAD_HANDLE);
+ }
+
+ votequorum_inst->finalize = 1;
+
+ hdb_handle_destroy (&votequorum_handle_t_db, handle);
+
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+
+cs_error_t votequorum_getinfo (
+ votequorum_handle_t handle,
+ unsigned int nodeid,
+ struct votequorum_info *info)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_getinfo req_lib_votequorum_getinfo;
+ struct res_lib_votequorum_getinfo res_lib_votequorum_getinfo;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_getinfo.header.size = sizeof (struct req_lib_votequorum_getinfo);
+ req_lib_votequorum_getinfo.header.id = MESSAGE_REQ_VOTEQUORUM_GETINFO;
+ req_lib_votequorum_getinfo.nodeid = nodeid;
+
+ iov.iov_base = (char *)&req_lib_votequorum_getinfo;
+ iov.iov_len = sizeof (struct req_lib_votequorum_getinfo);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_getinfo,
+ sizeof (struct res_lib_votequorum_getinfo), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_getinfo.header.error;
+
+ info->node_id = res_lib_votequorum_getinfo.nodeid;
+ info->node_state = res_lib_votequorum_getinfo.state;
+ info->node_votes = res_lib_votequorum_getinfo.votes;
+ info->node_expected_votes = res_lib_votequorum_getinfo.expected_votes;
+ info->highest_expected = res_lib_votequorum_getinfo.highest_expected;
+ info->total_votes = res_lib_votequorum_getinfo.total_votes;
+ info->quorum = res_lib_votequorum_getinfo.quorum;
+ info->flags = res_lib_votequorum_getinfo.flags;
+ info->qdevice_votes = res_lib_votequorum_getinfo.qdevice_votes;
+ memset(info->qdevice_name, 0, VOTEQUORUM_QDEVICE_MAX_NAME_LEN);
+ strcpy(info->qdevice_name, res_lib_votequorum_getinfo.qdevice_name);
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_setexpected (
+ votequorum_handle_t handle,
+ unsigned int expected_votes)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_setexpected req_lib_votequorum_setexpected;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+
+ req_lib_votequorum_setexpected.header.size = sizeof (struct req_lib_votequorum_setexpected);
+ req_lib_votequorum_setexpected.header.id = MESSAGE_REQ_VOTEQUORUM_SETEXPECTED;
+ req_lib_votequorum_setexpected.expected_votes = expected_votes;
+
+ iov.iov_base = (char *)&req_lib_votequorum_setexpected;
+ iov.iov_len = sizeof (struct req_lib_votequorum_setexpected);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_setvotes (
+ votequorum_handle_t handle,
+ unsigned int nodeid,
+ unsigned int votes)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_setvotes req_lib_votequorum_setvotes;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_setvotes.header.size = sizeof (struct req_lib_votequorum_setvotes);
+ req_lib_votequorum_setvotes.header.id = MESSAGE_REQ_VOTEQUORUM_SETVOTES;
+ req_lib_votequorum_setvotes.nodeid = nodeid;
+ req_lib_votequorum_setvotes.votes = votes;
+
+ iov.iov_base = (char *)&req_lib_votequorum_setvotes;
+ iov.iov_len = sizeof (struct req_lib_votequorum_setvotes);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_trackstart (
+ votequorum_handle_t handle,
+ uint64_t context,
+ unsigned int flags)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_trackstart req_lib_votequorum_trackstart;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_trackstart.header.size = sizeof (struct req_lib_votequorum_trackstart);
+ req_lib_votequorum_trackstart.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTART;
+ req_lib_votequorum_trackstart.track_flags = flags;
+ req_lib_votequorum_trackstart.context = context;
+
+ iov.iov_base = (char *)&req_lib_votequorum_trackstart;
+ iov.iov_len = sizeof (struct req_lib_votequorum_trackstart);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_trackstop (
+ votequorum_handle_t handle)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_general req_lib_votequorum_general;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_general.header.size = sizeof (struct req_lib_votequorum_general);
+ req_lib_votequorum_general.header.id = MESSAGE_REQ_VOTEQUORUM_TRACKSTOP;
+
+ iov.iov_base = (char *)&req_lib_votequorum_general;
+ iov.iov_len = sizeof (struct req_lib_votequorum_general);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+
+cs_error_t votequorum_context_get (
+ votequorum_handle_t handle,
+ void **context)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ *context = votequorum_inst->context;
+
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+cs_error_t votequorum_context_set (
+ votequorum_handle_t handle,
+ void *context)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ votequorum_inst->context = context;
+
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (CS_OK);
+}
+
+
+cs_error_t votequorum_fd_get (
+ votequorum_handle_t handle,
+ int *fd)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ error = qb_to_cs_error(qb_ipcc_fd_get (votequorum_inst->c, fd));
+
+ (void)hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_dispatch (
+ votequorum_handle_t handle,
+ cs_dispatch_flags_t dispatch_types)
+{
+ int timeout = -1;
+ cs_error_t error;
+ int cont = 1; /* always continue do loop except when set to 0 */
+ struct votequorum_inst *votequorum_inst;
+ votequorum_callbacks_t callbacks;
+ struct qb_ipc_response_header *dispatch_data;
+ struct res_lib_votequorum_quorum_notification *res_lib_votequorum_quorum_notification;
+ struct res_lib_votequorum_nodelist_notification *res_lib_votequorum_nodelist_notification;
+ struct res_lib_votequorum_expectedvotes_notification *res_lib_votequorum_expectedvotes_notification;
+ char dispatch_buf[IPC_DISPATCH_SIZE];
+ votequorum_ring_id_t ring_id;
+
+ if (dispatch_types != CS_DISPATCH_ONE &&
+ dispatch_types != CS_DISPATCH_ALL &&
+ dispatch_types != CS_DISPATCH_BLOCKING &&
+ dispatch_types != CS_DISPATCH_ONE_NONBLOCKING) {
+
+ return (CS_ERR_INVALID_PARAM);
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle,
+ (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ /*
+ * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
+ * wait indefinately for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
+ */
+ if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ timeout = 0;
+ }
+
+ dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
+ do {
+ error = qb_to_cs_error (qb_ipcc_event_recv (
+ votequorum_inst->c,
+ dispatch_buf,
+ IPC_DISPATCH_SIZE,
+ timeout));
+ if (error == CS_ERR_BAD_HANDLE) {
+ error = CS_OK;
+ goto error_put;
+ }
+ if (error == CS_ERR_TRY_AGAIN) {
+ if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ /*
+ * Don't mask error
+ */
+ goto error_put;
+ }
+ error = CS_OK;
+ if (dispatch_types == CS_DISPATCH_ALL) {
+ break; /* exit do while cont is 1 loop */
+ } else {
+ continue; /* next poll */
+ }
+ }
+ if (error != CS_OK) {
+ goto error_put;
+ }
+
+ /*
+ * Make copy of callbacks, message data, unlock instance, and call callback
+ * A risk of this dispatch method is that the callback routines may
+ * operate at the same time that votequorum_finalize has been called in another thread.
+ */
+ memcpy (&callbacks, &votequorum_inst->callbacks, sizeof (votequorum_callbacks_t));
+
+ /*
+ * Dispatch incoming message
+ */
+ switch (dispatch_data->id) {
+
+ case MESSAGE_RES_VOTEQUORUM_QUORUM_NOTIFICATION:
+ if (callbacks.votequorum_quorum_notify_fn == NULL) {
+ break;
+ }
+ res_lib_votequorum_quorum_notification = (struct res_lib_votequorum_quorum_notification *)dispatch_data;
+
+ callbacks.votequorum_quorum_notify_fn ( handle,
+ res_lib_votequorum_quorum_notification->context,
+ res_lib_votequorum_quorum_notification->quorate,
+ res_lib_votequorum_quorum_notification->node_list_entries,
+ (votequorum_node_t *)res_lib_votequorum_quorum_notification->node_list );
+ break;
+
+ case MESSAGE_RES_VOTEQUORUM_NODELIST_NOTIFICATION:
+ if (callbacks.votequorum_nodelist_notify_fn == NULL) {
+ break;
+ }
+ res_lib_votequorum_nodelist_notification = (struct res_lib_votequorum_nodelist_notification *)dispatch_data;
+ marshall_from_mar_votequorum_ring_id (&ring_id, &res_lib_votequorum_nodelist_notification->ring_id);
+
+ callbacks.votequorum_nodelist_notify_fn ( handle,
+ res_lib_votequorum_nodelist_notification->context,
+ ring_id,
+ res_lib_votequorum_nodelist_notification->node_list_entries,
+ res_lib_votequorum_nodelist_notification->node_list );
+ break;
+
+ case MESSAGE_RES_VOTEQUORUM_EXPECTEDVOTES_NOTIFICATION:
+ if (callbacks.votequorum_expectedvotes_notify_fn == NULL) {
+ break;
+ }
+ res_lib_votequorum_expectedvotes_notification = (struct res_lib_votequorum_expectedvotes_notification *)dispatch_data;
+
+ callbacks.votequorum_expectedvotes_notify_fn ( handle,
+ res_lib_votequorum_expectedvotes_notification->context,
+ res_lib_votequorum_expectedvotes_notification->expected_votes);
+ break;
+
+ default:
+ error = CS_ERR_LIBRARY;
+ goto error_put;
+ break;
+ }
+ if (votequorum_inst->finalize) {
+ /*
+ * If the finalize has been called then get out of the dispatch.
+ */
+ error = CS_ERR_BAD_HANDLE;
+ goto error_put;
+ }
+
+ /*
+ * Determine if more messages should be processed
+ */
+ if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
+ cont = 0;
+ }
+ } while (cont);
+
+
+error_put:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+ return (error);
+}
+
+cs_error_t votequorum_qdevice_register (
+ votequorum_handle_t handle,
+ const char *name)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_qdevice_register req_lib_votequorum_qdevice_register;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ if ((strlen(name) == 0) ||
+ (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+
+ req_lib_votequorum_qdevice_register.header.size = sizeof (struct req_lib_votequorum_qdevice_register);
+ req_lib_votequorum_qdevice_register.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_REGISTER;
+ strcpy(req_lib_votequorum_qdevice_register.name, name);
+
+ iov.iov_base = (char *)&req_lib_votequorum_qdevice_register;
+ iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_register);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_qdevice_poll (
+ votequorum_handle_t handle,
+ const char *name,
+ unsigned int cast_vote,
+ votequorum_ring_id_t ring_id)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_qdevice_poll req_lib_votequorum_qdevice_poll;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ if ((strlen(name) == 0) ||
+ (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_qdevice_poll.header.size = sizeof (struct req_lib_votequorum_qdevice_poll);
+ req_lib_votequorum_qdevice_poll.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_POLL;
+ strcpy(req_lib_votequorum_qdevice_poll.name, name);
+ req_lib_votequorum_qdevice_poll.cast_vote = cast_vote;
+ marshall_to_mar_votequorum_ring_id(&req_lib_votequorum_qdevice_poll.ring_id, &ring_id);
+
+ iov.iov_base = (char *)&req_lib_votequorum_qdevice_poll;
+ iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_poll);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_qdevice_master_wins (
+ votequorum_handle_t handle,
+ const char *name,
+ unsigned int allow)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_qdevice_master_wins req_lib_votequorum_qdevice_master_wins;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ if ((strlen(name) == 0) ||
+ (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_qdevice_master_wins.header.size = sizeof (struct req_lib_votequorum_qdevice_master_wins);
+ req_lib_votequorum_qdevice_master_wins.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_MASTER_WINS;
+ strcpy(req_lib_votequorum_qdevice_master_wins.name, name);
+ req_lib_votequorum_qdevice_master_wins.allow = allow;
+
+ iov.iov_base = (char *)&req_lib_votequorum_qdevice_master_wins;
+ iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_master_wins);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_qdevice_update (
+ votequorum_handle_t handle,
+ const char *oldname,
+ const char *newname)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_qdevice_update req_lib_votequorum_qdevice_update;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ if ((strlen(oldname) == 0) ||
+ (strlen(oldname) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN) ||
+ (strlen(newname) == 0) ||
+ (strlen(newname) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_qdevice_update.header.size = sizeof (struct req_lib_votequorum_qdevice_update);
+ req_lib_votequorum_qdevice_update.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_UPDATE;
+ strcpy(req_lib_votequorum_qdevice_update.oldname, oldname);
+ strcpy(req_lib_votequorum_qdevice_update.newname, newname);
+
+ iov.iov_base = (char *)&req_lib_votequorum_qdevice_update;
+ iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_update);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}
+
+cs_error_t votequorum_qdevice_unregister (
+ votequorum_handle_t handle,
+ const char *name)
+{
+ cs_error_t error;
+ struct votequorum_inst *votequorum_inst;
+ struct iovec iov;
+ struct req_lib_votequorum_qdevice_unregister req_lib_votequorum_qdevice_unregister;
+ struct res_lib_votequorum_status res_lib_votequorum_status;
+
+ if ((strlen(name) == 0) ||
+ (strlen(name) >= VOTEQUORUM_QDEVICE_MAX_NAME_LEN)) {
+ return CS_ERR_INVALID_PARAM;
+ }
+
+ error = hdb_error_to_cs(hdb_handle_get (&votequorum_handle_t_db, handle, (void *)&votequorum_inst));
+ if (error != CS_OK) {
+ return (error);
+ }
+
+ req_lib_votequorum_qdevice_unregister.header.size = sizeof (struct req_lib_votequorum_qdevice_unregister);
+ req_lib_votequorum_qdevice_unregister.header.id = MESSAGE_REQ_VOTEQUORUM_QDEVICE_UNREGISTER;
+ strcpy(req_lib_votequorum_qdevice_unregister.name, name);
+
+ iov.iov_base = (char *)&req_lib_votequorum_qdevice_unregister;
+ iov.iov_len = sizeof (struct req_lib_votequorum_qdevice_unregister);
+
+ error = qb_to_cs_error(qb_ipcc_sendv_recv (
+ votequorum_inst->c,
+ &iov,
+ 1,
+ &res_lib_votequorum_status,
+ sizeof (struct res_lib_votequorum_status), CS_IPC_TIMEOUT_MS));
+
+ if (error != CS_OK) {
+ goto error_exit;
+ }
+
+ error = res_lib_votequorum_status.header.error;
+
+error_exit:
+ hdb_handle_put (&votequorum_handle_t_db, handle);
+
+ return (error);
+}