Răsfoiți Sursa

Add dbus and snmp notifier

This is to send dbus events on major cluster events:
 - membership changes
 - application connect/dissconnet from corosync
 - quorum changes

dbus events can then be converted into snmp traps by foghorn or
corosync-notifyd can be run to directly send snmp traps.

Signed-off-by: Angus Salkeld <asalkeld@redhat.com>
Signed-off-by: Lon Hohberger <lhh@redhat.com>
Reviewed-by: Steven Dake <sdake@redhat.com>
Reviewed-by: Russell Bryant <russell@russellbryant.net>
Reviewed-by: Fabio M. Di Nitto <fdinitto@redhat.com>
Angus Salkeld 15 ani în urmă
părinte
comite
2a568d6e79

+ 50 - 0
INSTALL

@@ -123,6 +123,56 @@ balance:~/corosync/trunk% ./configure --enable-rdma
 Hopefully pkgconfig support is added in your distribution's version of
 Hopefully pkgconfig support is added in your distribution's version of
 libibverbs and librdmacm soon if you run into this problem.
 libibverbs and librdmacm soon if you run into this problem.
 
 
+-----------------------------------------
+* Building with SNMP/DBUS support *
+-----------------------------------------
+
+You can get SNMP traps on the following corosync events:
+1) node joine/leave
+2) application connect/dissconnect from corosync
+3) quorum gain/lost
+
+There are 2 modes of achieving this DBUS + foghorn and snmp-agentx.
+
+Setting up to get dbus events.
+------------------------------
+foghorn (http://git.fedorahosted.org/git/foghorn.git) converts
+dbus signals into snmp traps. So install foghorn.
+
+$ ./configure --enable-dbus
+$ make && sudo make install
+$ /etc/init.d/corosync start
+$ echo "OPTIONS=\"-d\"" > /etc/sysconfig/corosync-notifyd
+$ /etc/init.d/corosync-notifyd start
+Start foghorn
+
+to see the dbus signals getting sent try:
+$ dbus-monitor --system
+
+Setting up snmp-agentx.
+-----------------------
+If you don't want to use dbus then you can use snmp-agentx.
+
+$ ./configure --enable-snmp
+$ make && sudo make install
+$ /etc/init.d/corosync start
+$ vim /etc/snmp/snmptrapd.conf
+
+Add the following:
+authCommunity   log,execute,net public
+$ /etc/init.d/snmptrapd start
+$ echo "OPTIONS=\"-s\"" > /etc/sysconfig/corosync-notifyd
+$ /etc/init.d/corosync-notifyd start
+
+I start up wireshark to see if there are any snmp traps been sent
+as I am too lazy to setup a manager to receive traps.
+
+run a program that talks to corosync e.g.
+$ corosync-objctl
+
+And you should get traps
+
+
 ------------------------
 ------------------------
 * Configuring Corosync *
 * Configuring Corosync *
 ------------------------
 ------------------------

+ 1 - 1
Makefile.am

@@ -65,7 +65,7 @@ corolenstest_DATA	= conf/lenses/tests/test_corosync.aug
 endif
 endif
 
 
 SUBDIRS			= include lcr lib exec services tools test cts pkgconfig \
 SUBDIRS			= include lcr lib exec services tools test cts pkgconfig \
-			  man init
+			  man init conf
 
 
 install-exec-local:
 install-exec-local:
 	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/service.d
 	$(INSTALL) -d $(DESTDIR)/${COROSYSCONFDIR}/service.d

+ 3 - 2
TODO

@@ -46,13 +46,14 @@ automatically reenable a redundant ring when it has been back in service.
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
 topic-snmp
 topic-snmp
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
-Main Developer: Steven Dake
+Main Developer: Angus Salkeld
 Started: Not Started
 Started: Not Started
-Finished: 0%
+Finished: 100%
 target: needle
 target: needle
 Description:
 Description:
 This topic involves investigation of adding SNMP support into Corosync.
 This topic involves investigation of adding SNMP support into Corosync.
 
 
+
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------
 topic-udpu
 topic-udpu
 ------------------------------------------------------------------------------
 ------------------------------------------------------------------------------

+ 186 - 0
conf/COROSYNC-MIB.txt

@@ -0,0 +1,186 @@
+COROSYNC-MIB DEFINITIONS ::= BEGIN
+
+--
+-- MIB objects for the corosync
+--
+
+IMPORTS
+    MODULE-IDENTITY,NOTIFICATION-TYPE,
+    Integer32,enterprises                       FROM SNMPv2-SMI
+    TEXTUAL-CONVENTION                          FROM SNMPv2-TC
+    SnmpAdminString                             FROM SNMP-FRAMEWORK-MIB
+    netSnmp                                     FROM NET-SNMP-MIB
+    InetAddressType, InetAddress                FROM INET-ADDRESS-MIB
+;
+
+corosync MODULE-IDENTITY
+    LAST-UPDATED    "200911061318Z"
+    ORGANIZATION    "www.corosync.org"
+    CONTACT-INFO    "name:  Yuki Sato
+                     email: openais@lists.linux-foundation.org"
+    DESCRIPTION     "MIB objects for the corosync"
+    REVISION        "200911061318Z"
+    DESCRIPTION     "First draft"
+    REVISION        "201003251209Z"
+    DESCRIPTION
+        "Private Enterprise Number has been assigned."
+        ::= { enterprises 35488 }
+
+--
+-- top level structure
+--
+corosyncNotice OBJECT IDENTIFIER ::= { corosync 1 }
+
+--
+--  corosync MIB entries
+--
+
+--
+-- Node Information
+--
+corosyncNoticeNodeStatusTable OBJECT-TYPE
+    SYNTAX      SEQUENCE OF corosyncNoticeNodeEntry
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The table contains information about the nodes in the corosync."
+::= { corosyncNotice 1 }
+
+corosyncNoticeNodeEntry OBJECT-TYPE
+    SYNTAX      corosyncNoticeNodeEntry
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The entry containing information about the iface."
+    INDEX   { corosyncNoticeNodeIndex }
+::= { corosyncNoticeNodeStatusTable 1 }
+
+corosyncNoticeNodeEntry ::= SEQUENCE {
+    corosyncNoticeNodeIndex     Integer32,
+    corosyncNoticeNodeid        Integer32,
+    corosyncNoticeNode          OCTET STRING,
+    corosyncNoticeNodeStatus    INTEGER
+}
+
+corosyncNoticeNodeIndex OBJECT-TYPE
+    SYNTAX      Integer32
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION "The unique integer of the node."
+::= { corosyncNoticeNodeEntry 1 }
+
+corosyncNoticeNodeid OBJECT-TYPE
+    SYNTAX      Integer32
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION "The id of the node."
+::= { corosyncNoticeNodeEntry 2 }
+
+corosyncNoticeNode OBJECT-TYPE
+    SYNTAX      OCTET STRING (SIZE(1..64))
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The iface of the node."
+::= { corosyncNoticeNodeEntry 3 }
+
+corosyncNoticeNodeStatus OBJECT-TYPE
+    SYNTAX      INTEGER {
+                unknown (0),
+                joined  (1),
+                left    (2)
+            }
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The status change of the node."
+::= { corosyncNoticeNodeEntry 4 }
+
+--
+-- Iface(s) Information
+--
+corosyncNoticeIfaceStatusTable OBJECT-TYPE
+    SYNTAX      SEQUENCE OF corosyncNoticeIfaceEntry
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The table describes the iface(s) that are used by the corosync."
+::= { corosyncNotice 2 }
+
+corosyncNoticeIfaceEntry OBJECT-TYPE
+    SYNTAX      corosyncNoticeIfaceEntry
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The entry containing information about the iface."
+    INDEX   { corosyncNoticeIfaceIndex }
+::= { corosyncNoticeIfaceStatusTable 1 }
+
+corosyncNoticeIfaceEntry ::= SEQUENCE {
+    corosyncNoticeIfaceIndex    INTEGER,
+    corosyncNoticeIface         OCTET STRING,
+    corosyncNoticeIfaceStatus   OCTET STRING
+}
+
+corosyncNoticeIfaceIndex OBJECT-TYPE
+    SYNTAX      Integer32
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The unique integer of the iface(s)."
+::= { corosyncNoticeIfaceEntry 1 }
+
+corosyncNoticeIface OBJECT-TYPE
+    SYNTAX      OCTET STRING (SIZE(1..64))
+    MAX-ACCESS  accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The iface(s) of the change happened node."
+::= { corosyncNoticeIfaceEntry 2 }
+
+corosyncNoticeIfaceStatus OBJECT-TYPE
+    SYNTAX      INTEGER {
+                unknown (0),
+                up      (1),
+                down    (2),
+                faulty  (3)
+            }
+    MAX-ACCESS accessible-for-notify
+    STATUS      current
+    DESCRIPTION
+        "The status change of the iface."
+::= { corosyncNoticeIfaceEntry 3 }
+
+--corosyncNoticeIfaceStatus OBJECT-TYPE
+--   SYNTAX     OCTET STRING (SIZE(1..1024))
+--   MAX-ACCESS accessible-for-notify
+--   STATUS     current
+--   DESCRIPTION
+--       "The iface(s) status of the change happened node."
+--::= { corosyncNoticeIfaceEntry 3 }
+
+--
+-- Trap Information
+--
+corosyncNoticeTrap OBJECT IDENTIFIER ::= { corosync 100 }
+
+corosyncNoticeNodeTrap NOTIFICATION-TYPE
+    OBJECTS
+        { corosyncNoticeNodeid corosyncNoticeNode corosyncNoticeNodeStatus }
+    STATUS      current
+    DESCRIPTION
+        "The node status change event just happened."
+::= { corosyncNoticeTrap 1 }
+
+corosyncNoticeIfaceTrap NOTIFICATION-TYPE
+    OBJECTS
+        { corosyncNoticeNodeid corosyncNoticeIface corosyncNoticeIfaceStatus }
+    STATUS  current
+    DESCRIPTION
+        "The iface status change event just happened."
+::= { corosyncNoticeTrap 2 }
+
+END
+
+
+

+ 44 - 0
conf/Makefile.am

@@ -0,0 +1,44 @@
+# Copyright (c) 2009 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.
+
+EXTRA_DIST     = COROSYNC-MIB.txt corosync-signals.conf
+
+MAINTAINERCLEANFILES    = Makefile.in
+
+if INSTALL_MIB
+mibdir = $(datadir)/snmp/mibs
+mib_DATA = COROSYNC-MIB.txt
+endif
+
+if INSTALL_DBUSCONF
+dbusdir = $(sysconfdir)/dbus-1/system.d
+dbus_DATA = corosync-signals.conf
+endif

+ 26 - 0
conf/corosync-signals.conf

@@ -0,0 +1,26 @@
+<!DOCTYPE busconfig PUBLIC
+	  "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+	  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+
+	<!-- Only root can own the corosync service. -->
+	<policy user="root">
+		<allow own="org.corosync"/>
+	</policy>
+
+	<policy context="default">
+		<allow send_destination="org.corosync"
+		       send_path="/org/corosync"
+		       send_interface="org.corosync"
+		       send_member="NodeStateChange"/>
+		<allow send_destination="org.corosync"
+		       send_path="/org/corosync"
+		       send_interface="org.corosync"
+		       send_member="ConnectionStateChange"/>
+		<allow send_destination="org.corosync"
+		       send_path="/org/corosync"
+		       send_interface="org.corosync"
+		       send_member="QuorumStateChange"/>
+	</policy>
+
+</busconfig>

+ 73 - 1
configure.ac

@@ -130,7 +130,8 @@ AC_CONFIG_FILES([Makefile
 		 cts/Makefile
 		 cts/Makefile
 		 cts/agents/Makefile
 		 cts/agents/Makefile
 		 cts/CTSvars.py
 		 cts/CTSvars.py
-		 tools/Makefile])
+		 tools/Makefile
+		 conf/Makefile])
 
 
 ### Local business
 ### Local business
 
 
@@ -241,6 +242,10 @@ AC_ARG_ENABLE([nss],
 	[  --enable-nss                    : Network Security Services encryption. ],,
 	[  --enable-nss                    : Network Security Services encryption. ],,
 	[ enable_nss="yes" ])
 	[ enable_nss="yes" ])
 
 
+AC_ARG_ENABLE([dbus],
+	[  --enable-dbus                    : dbus events. ],,
+	[ enable_dbus="no" ])
+
 AC_ARG_ENABLE([testagents],
 AC_ARG_ENABLE([testagents],
 	[  --enable-testagents             : Install Test Agents. ],,
 	[  --enable-testagents             : Install Test Agents. ],,
 	[ default="no" ])
 	[ default="no" ])
@@ -281,6 +286,10 @@ AC_ARG_WITH([socket-dir],
 	[ SOCKETDIR="$withval" ],
 	[ SOCKETDIR="$withval" ],
 	[ SOCKETDIR="$localstatedir/run" ])
 	[ SOCKETDIR="$localstatedir/run" ])
 
 
+AC_ARG_ENABLE([snmp],
+       [  --enable-snmp           : SNMP protocol support ],
+       [ default="no" ])
+
 # OS detection
 # OS detection
 # THIS SECTION MUST DIE!
 # THIS SECTION MUST DIE!
 CP=cp
 CP=cp
@@ -385,6 +394,13 @@ if test "x${enable_nss}" = xyes; then
 	PACKAGE_FEATURES="$PACKAGE_FEATURES nss"
 	PACKAGE_FEATURES="$PACKAGE_FEATURES nss"
 fi
 fi
 
 
+# Look for dbus-1
+if test "x${enable_dbus}" = xyes; then
+	PKG_CHECK_MODULES([DBUS],[dbus-1])
+	AC_DEFINE_UNQUOTED([HAVE_DBUS], 1, [have dbus])
+	PACKAGE_FEATURES="$PACKAGE_FEATURES dbus"
+fi
+
 if test "x${enable_testagents}" = xyes; then
 if test "x${enable_testagents}" = xyes; then
 	AC_DEFINE_UNQUOTED([HAVE_TESTAGENTS], 1, [have testagents])
 	AC_DEFINE_UNQUOTED([HAVE_TESTAGENTS], 1, [have testagents])
 	PACKAGE_FEATURES="$PACKAGE_FEATURES testagents"
 	PACKAGE_FEATURES="$PACKAGE_FEATURES testagents"
@@ -425,6 +441,60 @@ if test "x${enable_augeas}" = xyes; then
 	PACKAGE_FEATURES="$PACKAGE_FEATURES augeas"
 	PACKAGE_FEATURES="$PACKAGE_FEATURES augeas"
 fi
 fi
 
 
+if test "x${enable_snmp}" = xyes; then
+       SNMPCONFIG=""
+       AC_CHECK_HEADERS(net-snmp/net-snmp-config.h)
+
+       if test "x${ac_cv_header_net_snmp_net_snmp_config_h}" != "xyes"; then
+               enable_snmp=no
+       fi
+
+       if test $enable_snmp != no; then
+               AC_PATH_PROGS(SNMPCONFIG, net-snmp-config)
+               if test "X${SNMPCONFIG}" = "X"; then
+                       AC_MSG_RESULT(You need the net_snmp development package to continue.)
+                       enable_snmp=no
+               fi
+       fi
+
+       if test $enable_snmp != no; then
+               AC_MSG_CHECKING(for special snmp libraries)
+               SNMPLIBS=`$SNMPCONFIG --libs`
+               AC_MSG_RESULT($SNMPLIBS)
+       fi
+
+       if test $enable_snmp != no; then
+               savedLibs=$LIBS
+               LIBS="$LIBS $SNMPLIBS"
+               AC_CHECK_FUNCS(netsnmp_transport_open_client)
+               if test $ac_cv_func_netsnmp_transport_open_client != yes; then
+                       AC_CHECK_FUNCS(netsnmp_tdomain_transport)
+                       if test $ac_cv_func_netsnmp_tdomain_transport != yes; then
+                               enable_snmp=no
+                       fi
+               else
+                       AC_DEFINE_UNQUOTED([NETSNMPV54], $NETSNMP_NEW_SUPPORT, [have net-snmp5.4 over])
+               fi
+               LIBS=$savedLibs
+       fi
+
+       AC_MSG_CHECKING(for snmp)
+       AC_MSG_RESULT($enable_snmp)
+   if test $enable_snmp = no; then
+               enable_snmp=0
+               AC_MSG_ERROR(Unable to support SNMP)
+   else
+               enable_snmp=1
+               PACKAGE_FEATURES="$PACKAGE_FEATURES snmp"
+               AC_DEFINE_UNQUOTED([ENABLE_SNMP], $enable_snmp, [Build in support for sending SNMP traps])
+   fi
+else
+       enable_snmp=0
+fi
+AC_SUBST([SNMPLIBS])
+AC_SUBST([SNMP_LCRSO])
+AM_CONDITIONAL(BUILD_SNMP, test "${enable_snmp}" = "1")
+
 # extra warnings
 # extra warnings
 EXTRA_WARNINGS=""
 EXTRA_WARNINGS=""
 
 
@@ -521,6 +591,8 @@ AC_SUBST([OS_DYFLAGS])
 
 
 AC_SUBST([OS_LDL])
 AC_SUBST([OS_LDL])
 AM_CONDITIONAL(INSTALL_TESTAGENTS, test -n "${enable_testagents}")
 AM_CONDITIONAL(INSTALL_TESTAGENTS, test -n "${enable_testagents}")
+AM_CONDITIONAL(INSTALL_MIB, test "${enable_snmp}" = "1")
+AM_CONDITIONAL(INSTALL_DBUSCONF, test "${enable_dbus}" = "1")
 AM_CONDITIONAL(AUGTOOL, test -n "${AUGTOOL}")
 AM_CONDITIONAL(AUGTOOL, test -n "${AUGTOOL}")
 AC_SUBST([NSS_LDFLAGS])
 AC_SUBST([NSS_LDFLAGS])
 
 

+ 23 - 0
corosync.spec.in

@@ -8,6 +8,8 @@
 %bcond_with testagents
 %bcond_with testagents
 %bcond_with watchdog
 %bcond_with watchdog
 %bcond_with monitoring
 %bcond_with monitoring
+%bcond_with snmp
+%bcond_with dbus
 
 
 Name: corosync
 Name: corosync
 Summary: The Corosync Cluster Engine and Application Programming Interfaces
 Summary: The Corosync Cluster Engine and Application Programming Interfaces
@@ -35,6 +37,12 @@ BuildRequires: autoconf automake
 %endif
 %endif
 BuildRequires: nss-devel
 BuildRequires: nss-devel
 BuildRequires: libibverbs-devel librdmacm-devel
 BuildRequires: libibverbs-devel librdmacm-devel
+%if %{with snmp}
+BuildRequires: net-snmp-devel
+%endif
+%if %{with dbus}
+BuildRequires: dbus-devel
+%endif
 
 
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX)
 
 
@@ -60,6 +68,12 @@ export rdmacm_LIBS=-lrdmacm \
 %endif
 %endif
 %if %{with monitoring}
 %if %{with monitoring}
 	--enable-monitoring \
 	--enable-monitoring \
+%endif
+%if %{with snmp}
+	--enable-snmp \
+%endif
+%if %{with dbus}
+	--enable-dbus \
 %endif
 %endif
 	--enable-rdma \
 	--enable-rdma \
 	--with-initddir=%{_initrddir}
 	--with-initddir=%{_initrddir}
@@ -107,13 +121,21 @@ fi
 %{_sbindir}/corosync-pload
 %{_sbindir}/corosync-pload
 %{_sbindir}/corosync-cpgtool
 %{_sbindir}/corosync-cpgtool
 %{_sbindir}/corosync-quorumtool
 %{_sbindir}/corosync-quorumtool
+%{_sbindir}/corosync-notifyd
 %{_bindir}/corosync-blackbox
 %{_bindir}/corosync-blackbox
 %dir %{_sysconfdir}/corosync
 %dir %{_sysconfdir}/corosync
 %dir %{_sysconfdir}/corosync/service.d
 %dir %{_sysconfdir}/corosync/service.d
 %dir %{_sysconfdir}/corosync/uidgid.d
 %dir %{_sysconfdir}/corosync/uidgid.d
 %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example
 %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example
 %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example.udpu
 %config(noreplace) %{_sysconfdir}/corosync/corosync.conf.example.udpu
+%if %{with dbus}
+%{_sysconfdir}/dbus-1/system.d/corosync-signals.conf
+%endif
+%if %{with snmp}
+%(_datadir)/snmp/mibs/COROSYNC-MIB.txt
+%endif
 %{_initrddir}/corosync
 %{_initrddir}/corosync
+%{_initrddir}/corosync-notifyd
 %dir %{_libexecdir}/lcrso
 %dir %{_libexecdir}/lcrso
 %{_libexecdir}/lcrso/coroparse.lcrso
 %{_libexecdir}/lcrso/coroparse.lcrso
 %{_libexecdir}/lcrso/objdb.lcrso
 %{_libexecdir}/lcrso/objdb.lcrso
@@ -143,6 +165,7 @@ fi
 %{_mandir}/man8/corosync-cpgtool.8*
 %{_mandir}/man8/corosync-cpgtool.8*
 %{_mandir}/man8/corosync-fplay.8*
 %{_mandir}/man8/corosync-fplay.8*
 %{_mandir}/man8/corosync-pload.8*
 %{_mandir}/man8/corosync-pload.8*
+%{_mandir}/man8/corosync-notifyd.8*
 %{_mandir}/man8/corosync-quorumtool.8*
 %{_mandir}/man8/corosync-quorumtool.8*
 %{_mandir}/man5/corosync.conf.5*
 %{_mandir}/man5/corosync.conf.5*
 
 

+ 1 - 0
cts/.gitignore

@@ -1,2 +1,3 @@
 CTSvars.py
 CTSvars.py
 *_test_agent
 *_test_agent
+*.pyc

+ 1 - 0
init/.gitignore

@@ -1 +1,2 @@
 generic
 generic
+notifyd

+ 4 - 3
init/Makefile.am

@@ -34,9 +34,9 @@
 
 
 MAINTAINERCLEANFILES	= Makefile.in
 MAINTAINERCLEANFILES	= Makefile.in
 
 
-EXTRA_DIST		= generic.in
+EXTRA_DIST		= generic.in notifyd.in
 
 
-target_INIT		= generic
+target_INIT		= generic notifyd
 
 
 %: %.in Makefile
 %: %.in Makefile
 	rm -f $@-t $@
 	rm -f $@-t $@
@@ -57,7 +57,8 @@ clean-local:
 install-exec-local:
 install-exec-local:
 	$(INSTALL) -d $(DESTDIR)/$(INITDDIR)
 	$(INSTALL) -d $(DESTDIR)/$(INITDDIR)
 	$(INSTALL) -m 755 generic $(DESTDIR)/$(INITDDIR)/corosync
 	$(INSTALL) -m 755 generic $(DESTDIR)/$(INITDDIR)/corosync
+	$(INSTALL) -m 755 notifyd $(DESTDIR)/$(INITDDIR)/corosync-notifyd
 
 
 uninstall-local:
 uninstall-local:
 	cd $(DESTDIR)/$(INITDDIR) && \
 	cd $(DESTDIR)/$(INITDDIR) && \
-		rm -f corosync
+		rm -f corosync corosync-notifyd

+ 147 - 0
init/notifyd.in

@@ -0,0 +1,147 @@
+#!/bin/bash
+
+# Authors:
+#  Angus Salkeld <asalkeld@redhat.com>
+#
+# License: Revised BSD
+
+# chkconfig: - 23 77
+# description: Corosync Dbus and snmp notifier
+# processname: corosync-notifyd
+#
+### BEGIN INIT INFO
+# Provides:		corosync-notifyd
+# Required-Start:	$corosync $cman
+# Required-Stop:	$corosync $cman
+# Default-Start:
+# Default-Stop:
+# Short-Description:	Starts and stops Corosync Notifier.
+# Description:		Starts and stops Corosync Notifier.
+### END INIT INFO
+
+desc="Corosync Notifier"
+prog="corosync-notifyd"
+
+# set secure PATH
+PATH="/sbin:/bin:/usr/sbin:/usr/bin:@SBINDIR@"
+
+success()
+{
+	echo -ne "[  OK  ]\r"
+}
+
+failure()
+{
+	echo -ne "[FAILED]\r"
+}
+
+status()
+{
+	pid=$(pidof $1 2>/dev/null)
+	rtrn=$?
+	if [ $rtrn -ne 0 ]; then
+		echo "$1 is stopped"
+	else
+		echo "$1 (pid $pid) is running..."
+	fi
+	return $rtrn
+}
+
+# rpm based distros
+if [ -d @SYSCONFDIR@/sysconfig ]; then
+	[ -f @INITDDIR@/functions ] && . @INITDDIR@/functions
+	[ -f @SYSCONFDIR@/sysconfig/$prog ] && . @SYSCONFDIR@/sysconfig/$prog
+	[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/subsys/$prog"
+fi
+
+# deb based distros
+if [ -d @SYSCONFDIR@/default ]; then
+	[ -f @SYSCONFDIR@/default/$prog ] && . @SYSCONFDIR@/default/$prog
+	[ -z "$LOCK_FILE" ] && LOCK_FILE="@LOCALSTATEDIR@/lock/$prog"
+fi
+
+# The version of __pids_pidof in /etc/init.d/functions calls pidof with -x
+# This means it matches scripts, including this one.
+# Redefine it here so that status (from the same file) works.
+# Otherwise simultaneous calls to stop() will loop forever
+__pids_pidof() {
+        pidof -c -o $$ -o $PPID -o %PPID "$1" || \
+                pidof -c -o $$ -o $PPID -o %PPID "${1##*/}"
+}
+
+start()
+{
+	echo -n "Starting $desc ($prog): "
+
+	# most recent distributions use tmpfs for @LOCALSTATEDIR@/run
+	# to avoid to clean it up on every boot.
+	# they also assume that init scripts will create
+	# required subdirectories for proper operations
+	mkdir -p @LOCALSTATEDIR@/run
+
+	if status $prog > /dev/null 2>&1; then
+		success
+	else
+		$prog $OPTIONS > /dev/null 2>&1
+
+		# give it time to fail
+		sleep 2
+		if status $prog > /dev/null 2>&1; then
+			touch $LOCK_FILE
+			success
+		else
+			failure
+			rtrn=1
+		fi
+	fi
+	echo
+}
+
+stop()
+{
+	! status $prog > /dev/null 2>&1 && return
+
+	echo -n "Signaling $desc ($prog) to terminate: "
+	kill -TERM $(pidof $prog) > /dev/null 2>&1
+	success
+	echo
+
+	rm -f $LOCK_FILE
+	success
+	echo
+}
+
+restart()
+{
+	stop
+	start
+}
+
+rtrn=0
+
+case "$1" in
+start)
+	start
+;;
+restart|reload|force-reload)
+	restart
+;;
+condrestart|try-restart)
+	if status $prog > /dev/null 2>&1; then
+		restart
+	fi
+;;
+status)
+	status $prog
+	rtrn=$?
+;;
+stop)
+	stop
+;;
+*)
+	echo "usage: $0 {start|stop|restart|reload|force-reload|condrestart|try-restart|status}"
+	rtrn=2
+;;
+esac
+
+exit $rtrn

+ 1 - 0
man/Makefile.am

@@ -47,6 +47,7 @@ dist_man_MANS = \
 	corosync-cpgtool.8 \
 	corosync-cpgtool.8 \
 	corosync-fplay.8 \
 	corosync-fplay.8 \
 	corosync-pload.8 \
 	corosync-pload.8 \
+	corosync-notifyd.8 \
 	corosync-quorumtool.8 \
 	corosync-quorumtool.8 \
 	corosync_overview.8 \
 	corosync_overview.8 \
 	cpg_overview.8 \
 	cpg_overview.8 \

+ 145 - 0
man/corosync-notifyd.8

@@ -0,0 +1,145 @@
+.\"/*
+.\" * Copyright (C) 2010 Red Hat, Inc.
+.\" *
+.\" * All rights reserved.
+.\" *
+.\" * Author: Angus Salkeld <asalkeld@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 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.
+.\" */
+.TH COROSYNC-NOTIFYD 8 2011-01-14
+.SH NAME
+corosync-notifyd \- Listen for important corosync events and send dbus and/or snmp traps.
+.SH SYNOPSIS
+.B "corosync-notifyd [\-f] [\-l] [\-o] [\-s] [\-m] [manager] [\-d] [-h]"
+.SH DESCRIPTION
+.B corosync-notifyd
+uses corosync API to listen for important cluster events and can log them,
+generate dbus signals or genterate snmp traps.
+.SH OPTIONS
+.TP
+.B -f
+Start application in foreground.
+.TP
+.B -l
+Log all events.
+.TP
+.B -o
+Print events to stdout (turns on -l).
+.TP
+.B -s
+Send SNMP traps on all events.
+.TP
+.B -m
+Set the SNMP manager address.
+.TP
+.B -d
+Send DBUS signals on all events.
+.TP
+.B -h
+Print this help
+.SH EXAMPLES
+.br
+$ corosync-notifyd -o
+.br
+corosync-notifyd[18505]: troll[23374016] corosync-notify:18505:12 is now connected to corosync
+.br
+corosync-notifyd[18505]: troll[23374016] corosync-notify:18505:13 is now disconnected from corosync
+.br
+corosync-notifyd[18505]: troll[23374016] is now quorate
+.br
+corosync-notifyd[18505]: r2[1550100672] ip:192.168.100.92 joined
+.br
+corosync-notifyd[18505]: r2[1550100672] ip:192.168.100.92 left
+.br
+
+.br
+$ corosync-notifyd -o
+.br
+
+Note this output below is from "dbus-monitor --system"
+
+.br
+signal sender=:1.216 -> dest=(null destination) serial=2 path=/com/redhat/cluster/corosync;
+ interface=com.redhat.cluster.corosync; member=ConnectionStateChange
+.br
+   string "troll"
+.br
+   uint32 23374016
+.br
+   string "corosync-notify:18900:12"
+.br
+   string "connected"
+.br
+signal sender=:1.216 -> dest=(null destination) serial=3 path=/com/redhat/cluster/corosync;
+ interface=com.redhat.cluster.corosync; member=ConnectionStateChange
+.br
+   string "troll"
+.br
+   uint32 23374016
+.br
+   string "corosync-notify:18900:13"
+.br
+   string "disconnected"
+.br
+signal sender=:1.216 -> dest=(null destination) serial=4 path=/com/redhat/cluster/corosync;
+ interface=com.redhat.cluster.corosync; member=QorumStateChange
+.br
+   string "troll"
+.br
+   uint32 23374016
+.br
+   string "quorate"
+.br
+signal sender=:1.216 -> dest=(null destination) serial=5 path=/com/redhat/cluster/corosync;
+ interface=com.redhat.cluster.corosync; member=NodeStateChange
+.br
+   string "r2"
+.br
+   uint32 1550100672
+.br
+   string "192.168.100.92"
+.br
+   string "joined"
+.br
+signal sender=:1.216 -> dest=(null destination) serial=6 path=/com/redhat/cluster/corosync;
+ interface=com.redhat.cluster.corosync; member=NodeStateChange
+.br
+   string "r2"
+.br
+   uint32 1550100672
+.br
+   string "192.168.100.92"
+.br
+   string "left"
+.SH SEE ALSO
+.BR corosync (8),
+.BR corosync-objctl (8),
+.BR dbus-monitor (1),
+.SH AUTHOR
+Angus Salkeld
+.PP

+ 1 - 0
tools/.gitignore

@@ -5,3 +5,4 @@ corosync-keygen
 corosync-objctl
 corosync-objctl
 corosync-pload
 corosync-pload
 corosync-quorumtool
 corosync-quorumtool
+corosync-notifyd

+ 15 - 4
tools/Makefile.am

@@ -30,15 +30,17 @@
 # THE POSSIBILITY OF SUCH DAMAGE.
 # THE POSSIBILITY OF SUCH DAMAGE.
 
 
 MAINTAINERCLEANFILES    = Makefile.in
 MAINTAINERCLEANFILES    = Makefile.in
-INCLUDES       		= -I$(top_builddir)/include  -I$(top_srcdir)/include
+INCLUDES       		= -I$(top_builddir)/include  -I$(top_srcdir)/include \
+                          -I$(top_builddir)/include/corosync
 
 
 sbin_PROGRAMS		= corosync-fplay corosync-cfgtool \
 sbin_PROGRAMS		= corosync-fplay corosync-cfgtool \
 			  corosync-keygen corosync-objctl \
 			  corosync-keygen corosync-objctl \
-			  corosync-pload corosync-cpgtool corosync-quorumtool
+			  corosync-pload corosync-cpgtool corosync-quorumtool \
+			  corosync-notifyd
 
 
 bin_SCRIPTS		= corosync-blackbox
 bin_SCRIPTS		= corosync-blackbox
 
 
-EXTRA_DIST		= $(bin_SCRIPTS)
+EXTRA_DIST		= $(bin_SCRIPTS) corosync-notifyd.sysconfig.example
 
 
 corosync_pload_LDADD	= -lpload -lcoroipcc
 corosync_pload_LDADD	= -lpload -lcoroipcc
 corosync_pload_LDFLAGS	= -L../lib
 corosync_pload_LDFLAGS	= -L../lib
@@ -52,5 +54,14 @@ corosync_quorumtool_LDADD = -lconfdb -lcfg -lquorum \
 			    -lvotequorum -lcoroipcc ../lcr/liblcr.a
 			    -lvotequorum -lcoroipcc ../lcr/liblcr.a
 corosync_quorumtool_LDFLAGS = -L../lib
 corosync_quorumtool_LDFLAGS = -L../lib
 
 
+corosync_notifyd_LDADD = -L../lib
+corosync_notifyd_LDFLAGS = -lcfg -lconfdb ../lcr/liblcr.a -lcoroipcc \
+			   ../exec/coropoll.o $(DBUS_LIBS) $(SNMPLIBS) \
+			   -lquorum
+corosync_notifyd_CPPFLAGS = $(DBUS_CFLAGS)
+
+
 lint:
 lint:
-	-splint $(LINT_FLAGS) $(CFLAGS) *.c
+	-splint $(LINT_FLAGS) $(DBUS_CFLAGS) $(INCLUDES) $(CFLAGS) *.c
+
+

+ 1040 - 0
tools/corosync-notifyd.c

@@ -0,0 +1,1040 @@
+/*
+ * Copyright (c) 2011 Red Hat
+ *
+ * All rights reserved.
+ *
+ * Author: Angus Salkeld <asalkeld@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 <sys/select.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/types.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <poll.h>
+#include <signal.h>
+#include <syslog.h>
+
+#include <corosync/corotypes.h>
+#include <corosync/totem/coropoll.h>
+#include <corosync/confdb.h>
+#include <corosync/cfg.h>
+#include <corosync/quorum.h>
+
+/*
+ * generic declarations
+ */
+enum {
+	CS_NTF_LOG,
+	CS_NTF_STDOUT,
+	CS_NTF_SNMP,
+	CS_NTF_DBUS,
+	CS_NTF_FG,
+	CS_NTF_MAX,
+};
+static int conf[CS_NTF_MAX];
+
+typedef void (*node_membership_fn_t)(char *nodename, uint32_t nodeid, char *state, char* ip);
+typedef void (*node_quorum_fn_t)(char *nodename, uint32_t nodeid, const char *state);
+typedef void (*application_connection_fn_t)(char *nodename, uint32_t nodeid, char *app_name, const char *state);
+
+struct notify_callbacks {
+	node_membership_fn_t node_membership_fn;
+	node_quorum_fn_t node_quorum_fn;
+	application_connection_fn_t application_connection_fn;
+};
+
+#define MAX_NOTIFIERS 5
+static int num_notifiers = 0;
+static struct notify_callbacks notifiers[MAX_NOTIFIERS];
+static uint32_t local_nodeid = 0;
+static char local_nodename[CS_MAX_NAME_LENGTH];
+static hdb_handle_t poll_handle;
+static quorum_handle_t quorum_handle;
+
+static void _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip);
+static void _cs_node_quorum_event(const char *state);
+static void _cs_application_connection_event(char *app_name, const char *state);
+
+#ifdef HAVE_DBUS
+#include <dbus/dbus.h>
+/*
+ * dbus
+ */
+#define DBUS_CS_NAME	"org.corosync"
+#define DBUS_CS_IFACE	"org.corosync"
+#define DBUS_CS_PATH	"/org/corosync"
+
+static DBusConnection *db = NULL;
+static char _err[512];
+static int err_set = 0;
+static void _cs_dbus_init(void);
+#endif /* HAVE_DBUS */
+
+#ifdef ENABLE_SNMP
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/snmpv3_api.h>
+#include <net-snmp/agent/agent_trap.h>
+#include <net-snmp/library/mib.h>
+#include <net-snmp/library/snmp_api.h>
+#include <net-snmp/library/snmp_client.h>
+#include <net-snmp/library/snmp_debug.h>
+
+enum snmp_node_status {
+       SNMP_NODE_STATUS_UNKNOWN = 0,
+       SNMP_NODE_STATUS_JOINED = 1,
+       SNMP_NODE_STATUS_LEFT = 2
+};
+
+#define SNMP_OID_COROSYNC "1.3.6.1.4.1.35488"
+#define SNMP_OID_NOTICE_ROOT SNMP_OID_COROSYNC ".1"
+#define SNMP_OID_NOTICE_NODE_TABLE  SNMP_OID_NOTICE_ROOT ".1"
+#define SNMP_OID_NOTICE_NODE_ENTRY  SNMP_OID_NOTICE_NODE_TABLE ".1"
+#define SNMP_OID_NOTICE_NODE_INDEX  SNMP_OID_NOTICE_NODE_ENTRY ".1"
+#define SNMP_OID_NOTICE_NODE_ID     SNMP_OID_NOTICE_NODE_ENTRY ".2"
+#define SNMP_OID_NOTICE_NODE        SNMP_OID_NOTICE_NODE_ENTRY ".3"
+#define SNMP_OID_NOTICE_NODE_STATE  SNMP_OID_NOTICE_NODE_ENTRY ".4"
+
+#define SNMP_OID_TRAPS_ROOT  SNMP_OID_COROSYNC ".100"
+#define SNMP_OID_TRAPS_NODE  SNMP_OID_TRAPS_ROOT ".1"
+
+#define CS_TIMESTAMP_STR_LEN 20
+static const char *local_host = "localhost";
+#endif /* ENABLE_SNMP */
+static char snmp_manager_buf[CS_MAX_NAME_LENGTH];
+static char *snmp_manager = NULL;
+
+
+/*
+ * confdb
+ */
+#define SEPERATOR_STR "."
+
+static confdb_handle_t confdb_handle;
+
+static void _cs_confdb_key_changed(confdb_handle_t handle,
+	confdb_change_type_t change_type,
+	hdb_handle_t parent_object_handle,
+	hdb_handle_t object_handle,
+	const void *object_name, size_t object_name_len,
+	const void *key_name, size_t key_name_len,
+	const void *key_value, size_t key_value_len);
+
+static void _cs_confdb_object_created(confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	hdb_handle_t object_handle,
+	const void *name_pt, size_t name_len);
+
+static void _cs_confdb_object_deleted(confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const void *name_pt, size_t name_len);
+
+static confdb_callbacks_t callbacks = {
+	.confdb_key_change_notify_fn = _cs_confdb_key_changed,
+	.confdb_object_create_change_notify_fn = _cs_confdb_object_created,
+	.confdb_object_delete_change_notify_fn = _cs_confdb_object_deleted,
+};
+
+static int32_t _cs_ip_to_hostname(char* ip, char* name_out)
+{
+	struct sockaddr_in sa;
+	int rc;
+
+	if (strchr(ip, ':') == NULL) {
+		sa.sin_family = AF_INET;
+	} else {
+		sa.sin_family = AF_INET6;
+	}
+
+	rc = inet_pton(sa.sin_family, ip, &sa.sin_addr);
+	if (rc == 0) {
+		return -EINVAL;
+	}
+
+	rc = getnameinfo((struct sockaddr*)&sa, sizeof(sa),
+			name_out, CS_MAX_NAME_LENGTH, NULL, 0, 0);
+	if (rc != 0) {
+		syslog (LOG_ERR, "error looking up %s : %s\n", ip, gai_strerror(rc));
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void
+_cs_confdb_key_changed(confdb_handle_t handle,
+	confdb_change_type_t change_type,
+	hdb_handle_t parent_object_handle,
+	hdb_handle_t object_handle,
+	const void *object_name_pt, size_t  object_name_len,
+	const void *key_name_pt, size_t key_name_len,
+	const void *key_value_pt, size_t key_value_len)
+{
+	char parent_name[CS_MAX_NAME_LENGTH];
+	size_t len = 0;
+	hdb_handle_t real_parent_object_handle;
+	cs_error_t rc = CS_OK;
+	char nodename[CS_MAX_NAME_LENGTH];
+	char nodeid_str[CS_MAX_NAME_LENGTH];
+	uint32_t nodeid;
+	char status[CS_MAX_NAME_LENGTH];
+	char ip[CS_MAX_NAME_LENGTH];
+	size_t ip_len;
+	confdb_value_types_t type;
+	char* open_bracket = NULL;
+	char* close_bracket = NULL;
+
+	rc = confdb_object_parent_get (handle,
+		parent_object_handle, &real_parent_object_handle);
+	assert(rc == CS_OK);
+
+	rc = confdb_object_name_get (handle,
+		real_parent_object_handle,
+		parent_name,
+		&len);
+	parent_name[len] = '\0';
+	assert(rc == CS_OK);
+
+	if (strcmp(parent_name, "members") == 0) {
+		if (strncmp(key_name_pt, "status", strlen("status")) == 0) {
+
+			memcpy(nodeid_str, object_name_pt, object_name_len);
+			nodeid_str[object_name_len] = '\0';
+			nodeid = atoi(nodeid_str);
+
+			memcpy(status, key_value_pt, key_value_len);
+			status[key_value_len] = '\0';
+
+			rc = confdb_key_get_typed(handle, parent_object_handle,
+				"ip", ip, &ip_len, &type);
+			assert(rc == CS_OK);
+			ip[ip_len-1] = '\0';
+
+			/*
+			 * We want the ip out of: "r(0) ip(192.168.100.92)"
+			 */
+			open_bracket = strrchr(ip, '(');
+			open_bracket++;
+			close_bracket = strrchr(open_bracket, ')');
+			*close_bracket = '\0';
+			_cs_ip_to_hostname(open_bracket, nodename);
+
+			_cs_node_membership_event(nodename, nodeid, status, open_bracket);
+		}
+	}
+}
+
+static void
+_cs_confdb_object_created(confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	hdb_handle_t object_handle,
+	const void *name_pt,
+	size_t name_len)
+{
+	char parent_name[CS_MAX_NAME_LENGTH];
+	size_t len = 0;
+	char obj_name[CS_MAX_NAME_LENGTH];
+	hdb_handle_t real_parent_object_handle;
+	cs_error_t rc = CS_OK;
+
+	memcpy(obj_name, name_pt, name_len);
+	obj_name[name_len] = '\0';
+
+	rc = confdb_object_parent_get (handle,
+		parent_object_handle, &real_parent_object_handle);
+	if (rc != CS_OK) {
+		/* this error is normally from our own cfg connection
+		 * which is short lived.
+		 */
+		return;
+	}
+
+	rc = confdb_object_name_get (handle,
+		real_parent_object_handle, parent_name, &len);
+	parent_name[len] = '\0';
+	assert(rc == CS_OK);
+
+	if (strcmp(parent_name, "connections") == 0) {
+		_cs_application_connection_event(obj_name, "connected");
+	}
+}
+
+static void
+_cs_confdb_object_deleted(confdb_handle_t handle,
+	hdb_handle_t parent_object_handle,
+	const void *name_pt,
+	size_t name_len)
+{
+	char obj_name[CS_MAX_NAME_LENGTH];
+	char parent_name[CS_MAX_NAME_LENGTH];
+	size_t len = 0;
+	cs_error_t rc;
+
+	memcpy(obj_name, name_pt, name_len);
+	obj_name[name_len] = '\0';
+
+	rc = confdb_object_name_get (handle,
+		parent_object_handle, parent_name, &len);
+	parent_name[len] = '\0';
+	assert(rc == CS_OK);
+
+	if (strcmp(parent_name, "connections") == 0) {
+		_cs_application_connection_event(obj_name, "disconnected");
+	}
+}
+
+static cs_error_t
+_cs_confdb_find_object (confdb_handle_t handle,
+	const char * name_pt,
+	hdb_handle_t * out_handle)
+{
+	char * obj_name_pt;
+	char * save_pt;
+	hdb_handle_t obj_handle;
+	confdb_handle_t parent_object_handle = OBJECT_PARENT_HANDLE;
+	char tmp_name[CS_MAX_NAME_LENGTH];
+	cs_error_t res = CS_OK;
+
+	strncpy (tmp_name, name_pt, CS_MAX_NAME_LENGTH);
+	obj_name_pt = strtok_r(tmp_name, SEPERATOR_STR, &save_pt);
+
+	while (obj_name_pt != NULL) {
+		res = confdb_object_find_start(handle, parent_object_handle);
+		if (res != CS_OK) {
+			syslog (LOG_ERR, "Could not start object_find %d\n", res);
+			exit (EXIT_FAILURE);
+		}
+
+		res = confdb_object_find(handle, parent_object_handle,
+				obj_name_pt, strlen (obj_name_pt), &obj_handle);
+		if (res != CS_OK) {
+			return res;
+		}
+
+		parent_object_handle = obj_handle;
+		obj_name_pt = strtok_r (NULL, SEPERATOR_STR, &save_pt);
+	}
+
+	*out_handle = parent_object_handle;
+	return res;
+}
+
+static int
+_cs_confdb_dispatch(hdb_handle_t handle,
+	int fd,	int revents, void *data)
+{
+	confdb_dispatch(confdb_handle, CONFDB_DISPATCH_ALL);
+	return 0;
+}
+
+static void _cs_quorum_notification(quorum_handle_t handle,
+	uint32_t quorate, uint64_t ring_seq,
+	uint32_t view_list_entries, uint32_t *view_list)
+{
+	if (quorate) {
+		_cs_node_quorum_event("quorate");
+	} else {
+		_cs_node_quorum_event("not quorate");
+	}
+}
+
+static int
+_cs_quorum_dispatch(hdb_handle_t handle,
+	int fd,	int revents, void *data)
+{
+	quorum_dispatch(quorum_handle, CS_DISPATCH_ALL);
+	return 0;
+}
+
+static void
+_cs_quorum_init(void)
+{
+	cs_error_t rc;
+	int fd;
+
+	quorum_callbacks_t quorum_callbacks = {
+		.quorum_notify_fn = _cs_quorum_notification,
+	};
+
+	rc = quorum_initialize (&quorum_handle, &quorum_callbacks);
+	if (rc != CS_OK) {
+		syslog(LOG_ERR, "Could not connect to corosync(quorum)");
+		return;
+	}
+	quorum_fd_get(quorum_handle, &fd);
+	poll_dispatch_add (poll_handle, fd, POLLIN|POLLNVAL, NULL,
+		_cs_quorum_dispatch);
+	quorum_trackstart(quorum_handle, CS_TRACK_CHANGES);
+}
+
+static void
+_cs_quorum_finalize(void)
+{
+	quorum_finalize (quorum_handle);
+}
+
+
+#ifdef HAVE_DBUS
+/*
+ * dbus notifications
+ */
+static void
+_cs_dbus_auto_flush(void)
+{
+	dbus_connection_ref(db);
+	dbus_connection_read_write(db, 500);
+	dbus_connection_unref(db);
+}
+
+static void
+_cs_dbus_release(void)
+{
+	DBusError err;
+
+	if (!db)
+		return;
+
+	dbus_error_init(&err);
+	dbus_bus_release_name(db, DBUS_CS_NAME, &err);
+	dbus_error_free(&err);
+	dbus_connection_unref(db);
+	db = NULL;
+}
+
+static void
+_cs_dbus_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
+{
+	DBusMessage *msg = NULL;
+	int ret = -1;
+
+	if (err_set) {
+		syslog (LOG_ERR, "%s\n", _err);
+		err_set = 0;
+	}
+
+	if (!db) {
+		goto out_free;
+	}
+
+	if (dbus_connection_get_is_connected(db) != TRUE) {
+		err_set = 1;
+		snprintf(_err, sizeof(_err), "DBus connection lost");
+		_cs_dbus_release();
+		goto out_unlock;
+	}
+
+	_cs_dbus_auto_flush();
+
+	if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
+					    DBUS_CS_IFACE,
+					    "QuorumStateChange"))) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	if (!dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &nodename,
+			DBUS_TYPE_UINT32, &nodeid,
+			DBUS_TYPE_STRING, &state,
+			DBUS_TYPE_INVALID)) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	dbus_connection_send(db, msg, NULL);
+	ret = 0;
+
+out_unlock:
+	if (ret == -1) {
+		syslog (LOG_ERR, "%s() error\n", __func__);
+	}
+	if (msg)
+		dbus_message_unref(msg);
+out_free:
+	return;
+}
+
+static void
+_cs_dbus_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
+{
+	DBusMessage *msg = NULL;
+	int ret = -1;
+
+	if (err_set) {
+		syslog (LOG_ERR, "%s\n", _err);
+		err_set = 0;
+	}
+
+	if (!db) {
+		goto out_free;
+	}
+
+	if (dbus_connection_get_is_connected(db) != TRUE) {
+		err_set = 1;
+		snprintf(_err, sizeof(_err), "DBus connection lost");
+		_cs_dbus_release();
+		goto out_unlock;
+	}
+
+	_cs_dbus_auto_flush();
+
+	if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
+					    DBUS_CS_IFACE,
+					    "NodeStateChange"))) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	if (!dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &nodename,
+			DBUS_TYPE_UINT32, &nodeid,
+			DBUS_TYPE_STRING, &ip,
+			DBUS_TYPE_STRING, &state,
+			DBUS_TYPE_INVALID)) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	dbus_connection_send(db, msg, NULL);
+	ret = 0;
+
+out_unlock:
+	if (ret == -1) {
+		syslog (LOG_ERR, "%s() error\n", __func__);
+	}
+	if (msg)
+		dbus_message_unref(msg);
+out_free:
+	return;
+}
+
+static void
+_cs_dbus_application_connection_event(char *nodename, uint32_t nodeid, char *app_name, const char *state)
+{
+	DBusMessage *msg = NULL;
+	int ret = -1;
+
+	if (err_set) {
+		syslog (LOG_ERR, "%s\n", _err);
+		err_set = 0;
+	}
+
+	if (!db) {
+		goto out_free;
+	}
+
+	if (dbus_connection_get_is_connected(db) != TRUE) {
+		err_set = 1;
+		snprintf(_err, sizeof(_err), "DBus connection lost");
+		_cs_dbus_release();
+		goto out_unlock;
+	}
+
+	_cs_dbus_auto_flush();
+
+	if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
+				DBUS_CS_IFACE,
+				"ConnectionStateChange"))) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	if (!dbus_message_append_args(msg,
+			DBUS_TYPE_STRING, &nodename,
+			DBUS_TYPE_UINT32, &nodeid,
+			DBUS_TYPE_STRING, &app_name,
+			DBUS_TYPE_STRING, &state,
+			DBUS_TYPE_INVALID)) {
+		syslog (LOG_ERR, "%s(%d) error\n", __func__, __LINE__);
+		goto out_unlock;
+	}
+
+	dbus_connection_send(db, msg, NULL);
+	ret = 0;
+
+out_unlock:
+	if (msg)
+		dbus_message_unref(msg);
+out_free:
+	return;
+}
+
+static void
+_cs_dbus_init(void)
+{
+	DBusConnection *dbc = NULL;
+	DBusError err;
+
+	dbus_error_init(&err);
+
+	dbc = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+	if (!dbc) {
+		snprintf(_err, sizeof(_err),
+			 "dbus_bus_get: %s", err.message);
+		err_set = 1;
+		dbus_error_free(&err);
+		return;
+	}
+
+	dbus_connection_set_exit_on_disconnect(dbc, FALSE);
+
+	db = dbc;
+
+	notifiers[num_notifiers].node_membership_fn =
+		_cs_dbus_node_membership_event;
+	notifiers[num_notifiers].node_quorum_fn =
+		_cs_dbus_node_quorum_event;
+	notifiers[num_notifiers].application_connection_fn =
+		_cs_dbus_application_connection_event;
+	num_notifiers++;
+}
+
+#endif /* HAVE_DBUS */
+
+#ifdef ENABLE_SNMP
+static netsnmp_session *snmp_init (const char *target)
+{
+	static netsnmp_session *session = NULL;
+#ifndef NETSNMPV54
+	char default_port[128];
+	snprintf (default_port, sizeof (default_port), "%s:162", target);
+#endif
+	if (session) {
+		return (session);
+	}
+
+	if (target == NULL) {
+		return NULL;
+	}
+
+	session = malloc (sizeof (netsnmp_session));
+	snmp_sess_init (session);
+	session->version = SNMP_VERSION_2c;
+	session->callback = NULL;
+	session->callback_magic = NULL;
+
+	session = snmp_add(session,
+#ifdef NETSNMPV54
+		netsnmp_transport_open_client ("snmptrap", target),
+#else
+		netsnmp_tdomain_transport (default_port, 0, "udp"),
+#endif
+		NULL, NULL);
+
+	if (session == NULL) {
+		syslog(LOG_ERR, "Could not create snmp transport");
+	}
+	return (session);
+}
+
+static inline void add_field (
+	netsnmp_pdu *trap_pdu,
+	u_char asn_type,
+	const char *prefix,
+	void *value,
+	size_t value_size)
+{
+	oid _oid[MAX_OID_LEN];
+	size_t _oid_len = MAX_OID_LEN;
+	if (snmp_parse_oid(prefix, _oid, &_oid_len)) {
+		snmp_pdu_add_variable (trap_pdu, _oid, _oid_len, asn_type, (u_char *) value, value_size);
+	}
+}
+
+static void
+_cs_snmp_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
+{
+	int ret;
+	char csysuptime[CS_TIMESTAMP_STR_LEN];
+	static oid snmptrap_oid[]  = { 1,3,6,1,6,3,1,1,4,1,0 };
+	static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
+	time_t now = time (NULL);
+	int node_status;
+
+	netsnmp_pdu *trap_pdu;
+	netsnmp_session *session = snmp_init (snmp_manager);
+	if (session == NULL) {
+		syslog (LOG_NOTICE, "Failed to init SNMP session.\n");
+		return ;
+	}
+
+	trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
+	if (!trap_pdu) {
+		syslog (LOG_NOTICE, "Failed to create SNMP notification.\n");
+		return ;
+	}
+
+	if (strcmp(state, "joined") == 0) {
+		node_status = SNMP_NODE_STATUS_JOINED;
+	} else if (strcmp(state, "left") == 0) {
+		node_status = SNMP_NODE_STATUS_LEFT;
+	} else {
+		node_status = SNMP_NODE_STATUS_UNKNOWN;
+	}
+
+	/* send uptime */
+	snprintf (csysuptime, CS_TIMESTAMP_STR_LEN, "%ld", now);
+	snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
+	snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_NODE);
+
+	/* Add extries to the trap */
+	add_field (trap_pdu, ASN_INTEGER, SNMP_OID_NOTICE_NODE_ID, (void*)&nodeid, sizeof (nodeid));
+	add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_NOTICE_NODE, (void*)ip, strlen (ip));
+	add_field (trap_pdu, ASN_INTEGER, SNMP_OID_NOTICE_NODE_STATE, (void*)&node_status, sizeof (node_status));
+
+	/* Send and cleanup */
+	ret = snmp_send (session, trap_pdu);
+	if (ret == 0) {
+		/* error */
+		syslog (LOG_ERR, "Could not send SNMP trap");
+		snmp_free_pdu (trap_pdu);
+	}
+}
+
+static void
+_cs_snmp_init(void)
+{
+	if (snmp_manager == NULL) {
+		snmp_manager = (char*)local_host;
+	}
+
+	notifiers[num_notifiers].node_membership_fn =
+		_cs_snmp_node_membership_event;
+	notifiers[num_notifiers].node_quorum_fn = NULL;
+	notifiers[num_notifiers].application_connection_fn = NULL;
+	num_notifiers++;
+}
+
+#endif /* ENABLE_SNMP */
+
+static void
+_cs_syslog_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
+{
+	syslog (LOG_NOTICE, "%s[%d] ip:%s %s\n", nodename, nodeid, ip, state);
+}
+
+static void
+_cs_syslog_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
+{
+	if (strcmp(state, "quorate") == 0) {
+		syslog (LOG_NOTICE, "%s[%d] is now %s\n", nodename, nodeid, state);
+	} else {
+		syslog (LOG_NOTICE, "%s[%d] has lost quorum\n", nodename, nodeid);
+	}
+}
+
+static void
+_cs_syslog_application_connection_event(char *nodename, uint32_t nodeid, char* app_name, const char *state)
+{
+	if (strcmp(state, "connected") == 0) {
+		syslog (LOG_ERR, "%s[%d] %s is now %s to corosync\n", nodename, nodeid, app_name, state);
+	} else {
+		syslog (LOG_ERR, "%s[%d] %s is now %s from corosync\n", nodename, nodeid, app_name, state);
+	}
+}
+
+static void
+_cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
+{
+	int i;
+
+	for (i = 0; i < num_notifiers; i++) {
+		if (notifiers[i].node_membership_fn) {
+			notifiers[i].node_membership_fn(nodename, nodeid, state, ip);
+		}
+	}
+}
+
+static void
+_cs_local_node_info_get(char **nodename, uint32_t *nodeid)
+{
+	cs_error_t rc;
+	corosync_cfg_handle_t cfg_handle;
+
+	if (local_nodeid == 0) {
+		corosync_cfg_initialize(&cfg_handle, NULL);
+		rc = corosync_cfg_local_get (cfg_handle, &local_nodeid);
+		corosync_cfg_finalize(cfg_handle);
+		if (rc != CS_OK) {
+			local_nodeid = 0;
+			strncpy(local_nodename, "localhost", CS_MAX_NAME_LENGTH);
+		} else {
+			gethostname(local_nodename, CS_MAX_NAME_LENGTH);
+		}
+	}
+	*nodeid = local_nodeid;
+	*nodename = local_nodename;
+}
+
+static void
+_cs_node_quorum_event(const char *state)
+{
+	int i;
+	char *nodename;
+	uint32_t nodeid;
+
+	_cs_local_node_info_get(&nodename, &nodeid);
+
+	for (i = 0; i < num_notifiers; i++) {
+		if (notifiers[i].node_quorum_fn) {
+			notifiers[i].node_quorum_fn(nodename, nodeid, state);
+		}
+	}
+}
+
+static void
+_cs_application_connection_event(char *app_name, const char *state)
+{
+	int i;
+	char *nodename;
+	uint32_t nodeid;
+
+	_cs_local_node_info_get(&nodename, &nodeid);
+
+	for (i = 0; i < num_notifiers; i++) {
+		if (notifiers[i].application_connection_fn) {
+			notifiers[i].application_connection_fn(nodename, nodeid, app_name, state);
+		}
+	}
+}
+
+static void
+sig_exit_handler (int num)
+{
+	poll_stop(poll_handle);
+}
+
+static void
+_cs_confdb_init(void)
+{
+	hdb_handle_t obj_handle;
+	cs_error_t rc;
+	int conf_fd = 0;
+
+	rc = confdb_initialize (&confdb_handle, &callbacks);
+	if (rc != CS_OK) {
+		syslog (LOG_ERR, "Failed to initialize the objdb API. Error %d\n", rc);
+		exit (EXIT_FAILURE);
+	}
+	confdb_fd_get(confdb_handle, &conf_fd);
+
+	poll_dispatch_add (poll_handle, conf_fd, POLLIN|POLLNVAL, NULL,
+		_cs_confdb_dispatch);
+
+	rc = _cs_confdb_find_object (confdb_handle, "runtime.connections.",
+		&obj_handle);
+	if (rc != CS_OK) {
+		syslog (LOG_ERR,
+			"Failed to find the connections object. Error %d\n", rc);
+		exit (EXIT_FAILURE);
+	}
+
+	rc = confdb_track_changes (confdb_handle, obj_handle,
+		CONFDB_TRACK_DEPTH_ONE);
+	if (rc != CS_OK) {
+		syslog (LOG_ERR,
+			"Failed to track the connections object. Error %d\n", rc);
+		exit (EXIT_FAILURE);
+	}
+	rc = _cs_confdb_find_object(confdb_handle,
+		"runtime.totem.pg.mrp.srp.members.", &obj_handle);
+	if (rc != CS_OK) {
+		syslog (LOG_ERR, "Failed to find the object. Error %d\n", rc);
+		exit (EXIT_FAILURE);
+	}
+
+	rc = confdb_track_changes(confdb_handle,
+		obj_handle, CONFDB_TRACK_DEPTH_RECURSIVE);
+	if (rc != CS_OK) {
+		syslog (LOG_ERR,
+			"Failed to track the object. Error %d\n", rc);
+		exit (EXIT_FAILURE);
+	}
+}
+
+static void
+_cs_confdb_finalize(void)
+{
+	confdb_stop_track_changes (confdb_handle);
+	confdb_finalize (confdb_handle);
+}
+
+static void
+_cs_check_config(void)
+{
+	if (conf[CS_NTF_LOG] == 0 &&
+		conf[CS_NTF_STDOUT] == 0 &&
+		conf[CS_NTF_SNMP] == 0 &&
+		conf[CS_NTF_DBUS] == 0) {
+		syslog(LOG_ERR, "no event type enabled, see corosync-notifyd -h, exiting.");
+		exit(EXIT_FAILURE);
+	}
+
+#ifndef ENABLE_SNMP
+	if (conf[CS_NTF_SNMP]) {
+		syslog(LOG_ERR, "Not compiled with SNMP support enabled, exiting.");
+		exit(EXIT_FAILURE);
+	}
+#endif
+#ifndef HAVE_DBUS
+	if (conf[CS_NTF_DBUS]) {
+		syslog(LOG_ERR, "Not compiled with DBus support enabled, exiting.");
+		exit(EXIT_FAILURE);
+	}
+#endif
+
+	if (conf[CS_NTF_STDOUT] && !conf[CS_NTF_FG]) {
+		syslog(LOG_ERR, "configured to print to stdout and run in the background, exiting");
+		exit(EXIT_FAILURE);
+	}
+	if (conf[CS_NTF_SNMP] && conf[CS_NTF_DBUS]) {
+		syslog(LOG_ERR, "configured to send snmp traps and dbus signals - are you sure?.");
+	}
+}
+
+static void
+_cs_usage(void)
+{
+	fprintf(stderr,	"usage:\n"\
+		"        -f     : Start application in foreground.\n"\
+		"        -l     : Log all events.\n"\
+		"        -o     : Print events to stdout (turns on -l).\n"\
+		"        -s     : Send SNMP traps on all events.\n"\
+		"        -m     : SNMP Manager IP address (defaults to localhost).\n"\
+		"        -d     : Send DBUS signals on all events.\n"\
+		"        -h     : Print this help\n\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+	int ch;
+
+	conf[CS_NTF_FG] = 0;
+	conf[CS_NTF_LOG] = 0;
+	conf[CS_NTF_STDOUT] = 0;
+	conf[CS_NTF_SNMP] = 0;
+	conf[CS_NTF_DBUS] = 0;
+
+	while ((ch = getopt (argc, argv, "floshdm:")) != EOF) {
+		switch (ch) {
+			case 'f':
+				conf[CS_NTF_FG] = 1;
+				break;
+			case 'l':
+				conf[CS_NTF_LOG] = 1;
+				break;
+			case 'm':
+				conf[CS_NTF_SNMP] = 1;
+				strncpy(snmp_manager_buf, optarg, CS_MAX_NAME_LENGTH);
+				snmp_manager = snmp_manager_buf;
+				break;
+			case 'o':
+				conf[CS_NTF_LOG] = 1;
+				conf[CS_NTF_STDOUT] = 1;
+				break;
+			case 's':
+				conf[CS_NTF_SNMP] = 1;
+				break;
+			case 'd':
+				conf[CS_NTF_DBUS] = 1;
+				break;
+			case 'h':
+			default:
+				_cs_usage();
+				return EXIT_FAILURE;
+		}
+	}
+
+	if (conf[CS_NTF_STDOUT]) {
+		openlog(NULL, LOG_PID|LOG_PERROR, LOG_DAEMON);
+	} else {
+		openlog(NULL, LOG_PID, LOG_DAEMON);
+	}
+	_cs_check_config();
+
+	if (!conf[CS_NTF_FG]) {
+		daemon(0, 0);
+	}
+
+	num_notifiers = 0;
+	if (conf[CS_NTF_LOG]) {
+		notifiers[num_notifiers].node_membership_fn =
+			_cs_syslog_node_membership_event;
+		notifiers[num_notifiers].node_quorum_fn =
+			_cs_syslog_node_quorum_event;
+		notifiers[num_notifiers].application_connection_fn =
+			_cs_syslog_application_connection_event;
+		num_notifiers++;
+	}
+
+	poll_handle = poll_create();
+
+	_cs_confdb_init();
+	_cs_quorum_init();
+
+#ifdef HAVE_DBUS
+	if (conf[CS_NTF_DBUS]) {
+		_cs_dbus_init();
+	}
+#endif /* HAVE_DBUS */
+
+#ifdef ENABLE_SNMP
+	if (conf[CS_NTF_SNMP]) {
+		_cs_snmp_init();
+	}
+#endif /* ENABLE_SNMP */
+
+	(void)signal (SIGINT, sig_exit_handler);
+	(void)signal (SIGQUIT, sig_exit_handler);
+	(void)signal (SIGTERM, sig_exit_handler);
+
+	poll_run(poll_handle);
+
+#ifdef HAVE_DBUS
+	if (conf[CS_NTF_DBUS]) {
+		_cs_dbus_release();
+	}
+#endif /* HAVE_DBUS */
+
+	_cs_quorum_finalize();
+	_cs_confdb_finalize();
+
+	return 0;
+}
+

+ 9 - 0
tools/corosync-notifyd.sysconfig.example

@@ -0,0 +1,9 @@
+#
+# See "man corosync-notifyd" for descriptions of
+# the options below.
+#
+# OPTIONS="-d -s -l -m <snmp manager address>"
+#
+
+OPTIONS=""
+