1 /*
2 * Copyright (c) 2011-2012 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Angus Salkeld <asalkeld@redhat.com>
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the MontaVista Software, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <config.h>
36
37 #include <sys/select.h>
38 #include <sys/socket.h>
39 #include <sys/un.h>
40 #include <sys/types.h>
41 #include <netdb.h>
42 #include <arpa/inet.h>
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <errno.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <poll.h>
51 #include <signal.h>
52
53 #include <qb/qbdefs.h>
54 #include <qb/qbloop.h>
55 #include <qb/qblog.h>
56
57 #include <corosync/corotypes.h>
58 #include <corosync/cfg.h>
59 #include <corosync/quorum.h>
60 #include <corosync/cmap.h>
61
62 /*
63 * generic declarations
64 */
65 enum {
66 CS_NTF_LOG,
67 CS_NTF_STDOUT,
68 CS_NTF_SNMP,
69 CS_NTF_DBUS,
70 CS_NTF_FG,
71 CS_NTF_NODNS,
72 CS_NTF_MAX,
73 };
74 static int conf[CS_NTF_MAX];
75
76 static int exit_code = 0;
77
78 static int32_t _cs_is_quorate = 0;
79
80 typedef void (*node_membership_fn_t)(char *nodename, uint32_t nodeid, char *state, char* ip);
81 typedef void (*node_quorum_fn_t)(char *nodename, uint32_t nodeid, const char *state);
82 typedef void (*application_connection_fn_t)(char *nodename, uint32_t nodeid, char *app_name, const char *state);
83 typedef void (*rrp_faulty_fn_t)(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state);
84
85 struct notify_callbacks {
86 node_membership_fn_t node_membership_fn;
87 node_quorum_fn_t node_quorum_fn;
88 application_connection_fn_t application_connection_fn;
89 rrp_faulty_fn_t rrp_faulty_fn;
90 };
91
92 #define MAX_NOTIFIERS 5
93 static int num_notifiers = 0;
94 static struct notify_callbacks notifiers[MAX_NOTIFIERS];
95 /*
96 * Global variable with local nodeid
97 */
98 static uint32_t g_local_nodeid = 0;
99 static char local_nodename[CS_MAX_NAME_LENGTH];
100 static qb_loop_t *main_loop;
101 static quorum_handle_t quorum_handle;
102
103 static void _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip);
104 static void _cs_node_quorum_event(const char *state);
105 static void _cs_application_connection_event(char *app_name, const char *state);
106 static void _cs_rrp_faulty_event(uint32_t iface_no, const char *state);
107
108 #ifdef HAVE_DBUS
109 #include <dbus/dbus.h>
110 /*
111 * dbus
112 */
113 #define DBUS_CS_NAME "org.corosync"
114 #define DBUS_CS_IFACE "org.corosync"
115 #define DBUS_CS_PATH "/org/corosync"
116
117 static DBusConnection *db = NULL;
118 static char _err[512];
119 static int err_set = 0;
120 static void _cs_dbus_init(void);
121 #endif /* HAVE_DBUS */
122
123 #ifdef ENABLE_SNMP
124 #include <net-snmp/net-snmp-config.h>
125 #include <net-snmp/snmpv3_api.h>
126 #include <net-snmp/agent/agent_trap.h>
127 #include <net-snmp/library/mib.h>
128 #include <net-snmp/library/snmp_api.h>
129 #include <net-snmp/library/snmp_client.h>
130 #include <net-snmp/library/snmp_debug.h>
131
132 enum snmp_node_status {
133 SNMP_NODE_STATUS_UNKNOWN = 0,
134 SNMP_NODE_STATUS_JOINED = 1,
135 SNMP_NODE_STATUS_LEFT = 2
136 };
137
138 #define SNMP_OID_COROSYNC "1.3.6.1.4.1.35488"
139 #define SNMP_OID_OBJECT_ROOT SNMP_OID_COROSYNC ".1"
140 #define SNMP_OID_OBJECT_NODE_NAME SNMP_OID_OBJECT_ROOT ".1"
141 #define SNMP_OID_OBJECT_NODE_ID SNMP_OID_OBJECT_ROOT ".2"
142 #define SNMP_OID_OBJECT_NODE_STATUS SNMP_OID_OBJECT_ROOT ".3"
143 #define SNMP_OID_OBJECT_NODE_ADDR SNMP_OID_OBJECT_ROOT ".4"
144
145 #define SNMP_OID_OBJECT_RINGSEQ SNMP_OID_OBJECT_ROOT ".20"
146 #define SNMP_OID_OBJECT_QUORUM SNMP_OID_OBJECT_ROOT ".21"
147
148 #define SNMP_OID_OBJECT_APP_NAME SNMP_OID_OBJECT_ROOT ".40"
149 #define SNMP_OID_OBJECT_APP_STATUS SNMP_OID_OBJECT_ROOT ".41"
150
151 #define SNMP_OID_OBJECT_RRP_IFACE_NO SNMP_OID_OBJECT_ROOT ".60"
152 #define SNMP_OID_OBJECT_RRP_STATUS SNMP_OID_OBJECT_ROOT ".61"
153
154 #define SNMP_OID_TRAPS_ROOT SNMP_OID_COROSYNC ".0"
155 #define SNMP_OID_TRAPS_NODE SNMP_OID_TRAPS_ROOT ".1"
156 #define SNMP_OID_TRAPS_QUORUM SNMP_OID_TRAPS_ROOT ".2"
157 #define SNMP_OID_TRAPS_APP SNMP_OID_TRAPS_ROOT ".3"
158 #define SNMP_OID_TRAPS_RRP SNMP_OID_TRAPS_ROOT ".4"
159
160 #define CS_TIMESTAMP_STR_LEN 20
161 static const char *local_host = "localhost";
162 #endif /* ENABLE_SNMP */
163 static char snmp_manager_buf[CS_MAX_NAME_LENGTH];
164 static char *snmp_manager = NULL;
165 static char snmp_community_buf[CS_MAX_NAME_LENGTH];
166 static char *snmp_community = NULL;
167
168 #define CMAP_MAX_RETRIES 10
169
170 /*
171 * cmap
172 */
173 static cmap_handle_t cmap_handle;
174 static cmap_track_handle_t cmap_track_handle_connections_key_changed;
175 static cmap_track_handle_t cmap_track_handle_members_key_changed;
176 static cmap_track_handle_t cmap_track_handle_rrp_faulty_key_changed;
177
_cs_ip_to_hostname(char * ip,char * name_out)178 static int32_t _cs_ip_to_hostname(char* ip, char* name_out)
179 {
180 struct sockaddr_in sa;
181 int rc;
182
183 if (strchr(ip, ':') == NULL) {
184 sa.sin_family = AF_INET;
185 } else {
186 sa.sin_family = AF_INET6;
187 }
188
189 rc = inet_pton(sa.sin_family, ip, &sa.sin_addr);
190 if (rc == 0) {
191 return -EINVAL;
192 }
193
194 rc = getnameinfo((struct sockaddr*)&sa, sizeof(sa),
195 name_out, CS_MAX_NAME_LENGTH, NULL, 0, 0);
196 if (rc != 0) {
197 qb_log(LOG_ERR, "error looking up %s : %s", ip, gai_strerror(rc));
198 return -EINVAL;
199 }
200 return 0;
201 }
202
_cs_cmap_members_key_changed(cmap_handle_t cmap_handle_c,cmap_track_handle_t cmap_track_handle,int32_t event,const char * key_name,struct cmap_notify_value new_value,struct cmap_notify_value old_value,void * user_data)203 static void _cs_cmap_members_key_changed (
204 cmap_handle_t cmap_handle_c,
205 cmap_track_handle_t cmap_track_handle,
206 int32_t event,
207 const char *key_name,
208 struct cmap_notify_value new_value,
209 struct cmap_notify_value old_value,
210 void *user_data)
211 {
212 char nodename[CS_MAX_NAME_LENGTH];
213 char* open_bracket = NULL;
214 char* close_bracket = NULL;
215 int res;
216 uint32_t nodeid;
217 char *ip_str;
218 char tmp_key[CMAP_KEYNAME_MAXLEN];
219 cs_error_t err;
220 int no_retries;
221
222 if (event != CMAP_TRACK_ADD && event != CMAP_TRACK_MODIFY) {
223 return ;
224 }
225
226 if (NULL == key_name) {
227 qb_log(LOG_ERR, "key_name: nil");
228 return ;
229 }
230
231 res = sscanf(key_name, "runtime.totem.pg.mrp.srp.members.%u.%s", &nodeid, tmp_key);
232 if (res != 2)
233 return ;
234
235 if (strcmp(tmp_key, "status") != 0) {
236 return ;
237 }
238
239 res = snprintf(tmp_key, CMAP_KEYNAME_MAXLEN, "runtime.totem.pg.mrp.srp.members.%u.ip", nodeid);
240 if (res <= 0 || res >= CMAP_KEYNAME_MAXLEN) {
241 qb_log(LOG_ERR, "temp_key: failed, res: %d, nodeid: %u", res, nodeid);
242 return ;
243 }
244 no_retries = 0;
245 while ((err = cmap_get_string(cmap_handle, tmp_key, &ip_str)) == CS_ERR_TRY_AGAIN &&
246 no_retries++ < CMAP_MAX_RETRIES) {
247 sleep(1);
248 }
249
250 if (err != CS_OK) {
251 return ;
252 }
253 /*
254 * We want the ip out of: "r(0) ip(192.168.100.92)"
255 */
256 open_bracket = strrchr(ip_str, '(');
257 if (NULL == open_bracket) {
258 qb_log(LOG_ERR, "ip_str: %s", ip_str);
259 free(ip_str);
260 return ;
261 }
262 open_bracket++;
263 close_bracket = strchr(open_bracket, ')');
264 if (NULL == close_bracket) {
265 qb_log(LOG_ERR, "open_bracket: %s", open_bracket);
266 free(ip_str);
267 return ;
268 }
269 *close_bracket = '\0';
270 if(conf[CS_NTF_NODNS]) {
271 strncpy(nodename, open_bracket, CS_MAX_NAME_LENGTH-1);
272 } else {
273 res = _cs_ip_to_hostname(open_bracket, nodename);
274 if (res) {
275 strncpy(nodename, open_bracket, CS_MAX_NAME_LENGTH-1);
276 }
277 }
278 _cs_node_membership_event(nodename, nodeid, (char *)new_value.data, open_bracket);
279 free(ip_str);
280 }
281
_cs_cmap_connections_key_changed(cmap_handle_t cmap_handle_c,cmap_track_handle_t cmap_track_handle,int32_t event,const char * key_name,struct cmap_notify_value new_value,struct cmap_notify_value old_value,void * user_data)282 static void _cs_cmap_connections_key_changed (
283 cmap_handle_t cmap_handle_c,
284 cmap_track_handle_t cmap_track_handle,
285 int32_t event,
286 const char *key_name,
287 struct cmap_notify_value new_value,
288 struct cmap_notify_value old_value,
289 void *user_data)
290 {
291 char obj_name[CS_MAX_NAME_LENGTH];
292 char conn_str[CMAP_KEYNAME_MAXLEN];
293 char tmp_key[CMAP_KEYNAME_MAXLEN];
294 int res;
295
296 res = sscanf(key_name, "runtime.connections.%[^.].%s", conn_str, tmp_key);
297 if (res != 2) {
298 return ;
299 }
300
301 if (strcmp(tmp_key, "service_id") != 0) {
302 return ;
303 }
304
305 snprintf(obj_name, CS_MAX_NAME_LENGTH, "%s", conn_str);
306
307 if (event == CMAP_TRACK_ADD) {
308 _cs_application_connection_event(obj_name, "connected");
309 }
310
311 if (event == CMAP_TRACK_DELETE) {
312 _cs_application_connection_event(obj_name, "disconnected");
313 }
314 }
315
_cs_cmap_rrp_faulty_key_changed(cmap_handle_t cmap_handle_c,cmap_track_handle_t cmap_track_handle,int32_t event,const char * key_name,struct cmap_notify_value new_value,struct cmap_notify_value old_value,void * user_data)316 static void _cs_cmap_rrp_faulty_key_changed (
317 cmap_handle_t cmap_handle_c,
318 cmap_track_handle_t cmap_track_handle,
319 int32_t event,
320 const char *key_name,
321 struct cmap_notify_value new_value,
322 struct cmap_notify_value old_value,
323 void *user_data)
324 {
325 uint32_t iface_no;
326 char tmp_key[CMAP_KEYNAME_MAXLEN];
327 int res;
328 int no_retries;
329 uint8_t faulty;
330 cs_error_t err;
331
332 res = sscanf(key_name, "runtime.totem.pg.mrp.rrp.%u.%s", &iface_no, tmp_key);
333 if (res != 2) {
334 return ;
335 }
336
337 if (strcmp(tmp_key, "faulty") != 0) {
338 return ;
339 }
340
341 no_retries = 0;
342 while ((err = cmap_get_uint8(cmap_handle, key_name, &faulty)) == CS_ERR_TRY_AGAIN &&
343 no_retries++ < CMAP_MAX_RETRIES) {
344 sleep(1);
345 }
346
347 if (err != CS_OK) {
348 return ;
349 }
350
351 if (faulty) {
352 _cs_rrp_faulty_event(iface_no, "faulty");
353 } else {
354 _cs_rrp_faulty_event(iface_no, "operational");
355 }
356 }
357
358 static int
_cs_cmap_dispatch(int fd,int revents,void * data)359 _cs_cmap_dispatch(int fd, int revents, void *data)
360 {
361 cs_error_t err;
362
363 err = cmap_dispatch(cmap_handle, CS_DISPATCH_ONE);
364
365 if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT &&
366 err != CS_ERR_QUEUE_FULL) {
367 qb_log(LOG_ERR, "Could not dispatch cmap events. Error %u", err);
368 qb_loop_stop(main_loop);
369
370 exit_code = 1;
371
372 return -1;
373 }
374
375 return 0;
376 }
377
_cs_quorum_notification(quorum_handle_t handle,uint32_t quorate,uint64_t ring_seq,uint32_t view_list_entries,uint32_t * view_list)378 static void _cs_quorum_notification(quorum_handle_t handle,
379 uint32_t quorate, uint64_t ring_seq,
380 uint32_t view_list_entries, uint32_t *view_list)
381 {
382 if (_cs_is_quorate == quorate) {
383 return;
384 }
385 _cs_is_quorate = quorate;
386
387 if (quorate) {
388 _cs_node_quorum_event("quorate");
389 } else {
390 _cs_node_quorum_event("not quorate");
391 }
392 }
393
394 static int
_cs_quorum_dispatch(int fd,int revents,void * data)395 _cs_quorum_dispatch(int fd, int revents, void *data)
396 {
397 cs_error_t err;
398
399 err = quorum_dispatch(quorum_handle, CS_DISPATCH_ONE);
400 if (err != CS_OK && err != CS_ERR_TRY_AGAIN && err != CS_ERR_TIMEOUT &&
401 err != CS_ERR_QUEUE_FULL) {
402 qb_log(LOG_ERR, "Could not dispatch quorum events. Error %u", err);
403 qb_loop_stop(main_loop);
404
405 exit_code = 1;
406
407 return -1;
408 }
409 return 0;
410 }
411
412 static void
_cs_quorum_init(void)413 _cs_quorum_init(void)
414 {
415 cs_error_t rc;
416 uint32_t quorum_type;
417 int fd;
418
419 quorum_callbacks_t quorum_callbacks = {
420 .quorum_notify_fn = _cs_quorum_notification,
421 };
422
423 rc = quorum_initialize (&quorum_handle, &quorum_callbacks,
424 &quorum_type);
425 if (rc != CS_OK) {
426 qb_log(LOG_ERR, "Could not connect to corosync(quorum)");
427 return;
428 }
429 quorum_fd_get(quorum_handle, &fd);
430 qb_loop_poll_add(main_loop, QB_LOOP_MED, fd, POLLIN|POLLNVAL, NULL,
431 _cs_quorum_dispatch);
432 rc = quorum_trackstart(quorum_handle, CS_TRACK_CHANGES);
433 if (rc != CS_OK) {
434 qb_log(LOG_ERR, "Could not start tracking");
435 return;
436 }
437 }
438
439 static void
_cs_quorum_finalize(void)440 _cs_quorum_finalize(void)
441 {
442 quorum_finalize (quorum_handle);
443 }
444
445
446 #ifdef HAVE_DBUS
447 /*
448 * dbus notifications
449 */
450 static void
_cs_dbus_auto_flush(void)451 _cs_dbus_auto_flush(void)
452 {
453 dbus_connection_ref(db);
454 while (dbus_connection_get_dispatch_status(db) == DBUS_DISPATCH_DATA_REMAINS) {
455 dbus_connection_dispatch(db);
456 }
457
458 while (dbus_connection_has_messages_to_send(db)) {
459 dbus_connection_flush(db);
460 }
461
462 dbus_connection_unref(db);
463 }
464
465 static void
_cs_dbus_release(void)466 _cs_dbus_release(void)
467 {
468 DBusError err;
469
470 if (!db)
471 return;
472
473 dbus_error_init(&err);
474 dbus_bus_release_name(db, DBUS_CS_NAME, &err);
475 dbus_error_free(&err);
476 dbus_connection_unref(db);
477 db = NULL;
478 }
479
480 static void
_cs_dbus_node_quorum_event(char * nodename,uint32_t nodeid,const char * state)481 _cs_dbus_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
482 {
483 DBusMessage *msg = NULL;
484
485 if (err_set) {
486 qb_log(LOG_ERR, "%s", _err);
487 err_set = 0;
488 }
489
490 if (!db) {
491 goto out_free;
492 }
493
494 if (dbus_connection_get_is_connected(db) != TRUE) {
495 err_set = 1;
496 snprintf(_err, sizeof(_err), "DBus connection lost");
497 _cs_dbus_release();
498 goto out_unlock;
499 }
500
501 _cs_dbus_auto_flush();
502
503 if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
504 DBUS_CS_IFACE,
505 "QuorumStateChange"))) {
506 qb_log(LOG_ERR, "error creating dbus signal");
507 goto out_unlock;
508 }
509
510 if (!dbus_message_append_args(msg,
511 DBUS_TYPE_STRING, &nodename,
512 DBUS_TYPE_UINT32, &nodeid,
513 DBUS_TYPE_STRING, &state,
514 DBUS_TYPE_INVALID)) {
515 qb_log(LOG_ERR, "error adding args to quorum signal");
516 goto out_unlock;
517 }
518
519 dbus_connection_send(db, msg, NULL);
520
521 out_unlock:
522 if (msg) {
523 dbus_message_unref(msg);
524 }
525 out_free:
526 return;
527 }
528
529 static void
_cs_dbus_node_membership_event(char * nodename,uint32_t nodeid,char * state,char * ip)530 _cs_dbus_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
531 {
532 DBusMessage *msg = NULL;
533
534 if (err_set) {
535 qb_log(LOG_ERR, "%s", _err);
536 err_set = 0;
537 }
538
539 if (!db) {
540 goto out_free;
541 }
542
543 if (dbus_connection_get_is_connected(db) != TRUE) {
544 err_set = 1;
545 snprintf(_err, sizeof(_err), "DBus connection lost");
546 _cs_dbus_release();
547 goto out_unlock;
548 }
549
550 _cs_dbus_auto_flush();
551
552 if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
553 DBUS_CS_IFACE,
554 "NodeStateChange"))) {
555 qb_log(LOG_ERR, "error creating NodeStateChange signal");
556 goto out_unlock;
557 }
558
559 if (!dbus_message_append_args(msg,
560 DBUS_TYPE_STRING, &nodename,
561 DBUS_TYPE_UINT32, &nodeid,
562 DBUS_TYPE_STRING, &ip,
563 DBUS_TYPE_STRING, &state,
564 DBUS_TYPE_INVALID)) {
565 qb_log(LOG_ERR, "error adding args to NodeStateChange signal");
566 goto out_unlock;
567 }
568
569 dbus_connection_send(db, msg, NULL);
570
571 out_unlock:
572 if (msg) {
573 dbus_message_unref(msg);
574 }
575 out_free:
576 return;
577 }
578
579 static void
_cs_dbus_application_connection_event(char * nodename,uint32_t nodeid,char * app_name,const char * state)580 _cs_dbus_application_connection_event(char *nodename, uint32_t nodeid, char *app_name, const char *state)
581 {
582 DBusMessage *msg = NULL;
583
584 if (err_set) {
585 qb_log(LOG_ERR, "%s", _err);
586 err_set = 0;
587 }
588
589 if (!db) {
590 goto out_free;
591 }
592
593 if (dbus_connection_get_is_connected(db) != TRUE) {
594 err_set = 1;
595 snprintf(_err, sizeof(_err), "DBus connection lost");
596 _cs_dbus_release();
597 goto out_unlock;
598 }
599
600 _cs_dbus_auto_flush();
601
602 if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
603 DBUS_CS_IFACE,
604 "ConnectionStateChange"))) {
605 qb_log(LOG_ERR, "error creating ConnectionStateChange signal");
606 goto out_unlock;
607 }
608
609 if (!dbus_message_append_args(msg,
610 DBUS_TYPE_STRING, &nodename,
611 DBUS_TYPE_UINT32, &nodeid,
612 DBUS_TYPE_STRING, &app_name,
613 DBUS_TYPE_STRING, &state,
614 DBUS_TYPE_INVALID)) {
615 qb_log(LOG_ERR, "error adding args to ConnectionStateChange signal");
616 goto out_unlock;
617 }
618
619 dbus_connection_send(db, msg, NULL);
620
621 out_unlock:
622 if (msg) {
623 dbus_message_unref(msg);
624 }
625 out_free:
626 return;
627 }
628
629 static void
_cs_dbus_rrp_faulty_event(char * nodename,uint32_t nodeid,uint32_t iface_no,const char * state)630 _cs_dbus_rrp_faulty_event(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state)
631 {
632 DBusMessage *msg = NULL;
633
634 if (err_set) {
635 qb_log(LOG_ERR, "%s", _err);
636 err_set = 0;
637 }
638
639 if (!db) {
640 goto out_free;
641 }
642
643 if (dbus_connection_get_is_connected(db) != TRUE) {
644 err_set = 1;
645 snprintf(_err, sizeof(_err), "DBus connection lost");
646 _cs_dbus_release();
647 goto out_unlock;
648 }
649
650 _cs_dbus_auto_flush();
651
652 if (!(msg = dbus_message_new_signal(DBUS_CS_PATH,
653 DBUS_CS_IFACE,
654 "QuorumStateChange"))) {
655 qb_log(LOG_ERR, "error creating dbus signal");
656 goto out_unlock;
657 }
658
659 if (!dbus_message_append_args(msg,
660 DBUS_TYPE_STRING, &nodename,
661 DBUS_TYPE_UINT32, &nodeid,
662 DBUS_TYPE_UINT32, &iface_no,
663 DBUS_TYPE_STRING, &state,
664 DBUS_TYPE_INVALID)) {
665 qb_log(LOG_ERR, "error adding args to rrp signal");
666 goto out_unlock;
667 }
668
669 dbus_connection_send(db, msg, NULL);
670
671 out_unlock:
672 if (msg) {
673 dbus_message_unref(msg);
674 }
675 out_free:
676 return;
677 }
678
679 static void
_cs_dbus_init(void)680 _cs_dbus_init(void)
681 {
682 DBusConnection *dbc = NULL;
683 DBusError err;
684
685 dbus_error_init(&err);
686
687 dbc = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
688 if (!dbc) {
689 snprintf(_err, sizeof(_err),
690 "dbus_bus_get: %s", err.message);
691 err_set = 1;
692 dbus_error_free(&err);
693 return;
694 }
695
696 dbus_connection_set_exit_on_disconnect(dbc, FALSE);
697
698 db = dbc;
699
700 notifiers[num_notifiers].node_membership_fn =
701 _cs_dbus_node_membership_event;
702 notifiers[num_notifiers].node_quorum_fn =
703 _cs_dbus_node_quorum_event;
704 notifiers[num_notifiers].application_connection_fn =
705 _cs_dbus_application_connection_event;
706 notifiers[num_notifiers].rrp_faulty_fn =
707 _cs_dbus_rrp_faulty_event;
708
709 num_notifiers++;
710 }
711
712 #endif /* HAVE_DBUS */
713
714 #ifdef ENABLE_SNMP
snmp_init(const char * target)715 static netsnmp_session *snmp_init (const char *target)
716 {
717 static netsnmp_session *session = NULL;
718 #ifndef NETSNMPV54
719 char default_port[128];
720 snprintf (default_port, sizeof (default_port), "%s:162", target);
721 #endif
722 if (session) {
723 return (session);
724 }
725
726 if (target == NULL) {
727 return NULL;
728 }
729
730 session = malloc (sizeof (netsnmp_session));
731 snmp_sess_init (session);
732 session->version = SNMP_VERSION_2c;
733 session->callback = NULL;
734 session->callback_magic = NULL;
735
736 if (snmp_community) {
737 session->community = (u_char *)snmp_community;
738 session->community_len = strlen(snmp_community_buf);
739 }
740
741 session = snmp_add(session,
742 #ifdef NETSNMPV54
743 netsnmp_transport_open_client ("snmptrap", target),
744 #else
745 netsnmp_tdomain_transport (default_port, 0, "udp"),
746 #endif
747 NULL, NULL);
748
749 if (session == NULL) {
750 qb_log(LOG_ERR, 0, "Could not create snmp transport");
751 }
752 return (session);
753 }
754
add_field(netsnmp_pdu * trap_pdu,u_char asn_type,const char * prefix,void * value,size_t value_size)755 static inline void add_field (
756 netsnmp_pdu *trap_pdu,
757 u_char asn_type,
758 const char *prefix,
759 void *value,
760 size_t value_size)
761 {
762 oid _oid[MAX_OID_LEN];
763 size_t _oid_len = MAX_OID_LEN;
764 if (snmp_parse_oid(prefix, _oid, &_oid_len)) {
765 snmp_pdu_add_variable (trap_pdu, _oid, _oid_len, asn_type, (u_char *) value, value_size);
766 }
767 }
768
769 static void
_cs_snmp_node_membership_event(char * nodename,uint32_t nodeid,char * state,char * ip)770 _cs_snmp_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
771 {
772 int ret;
773 char csysuptime[CS_TIMESTAMP_STR_LEN];
774 static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
775 static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
776 time_t now = time (NULL);
777
778 netsnmp_pdu *trap_pdu;
779 netsnmp_session *session = snmp_init (snmp_manager);
780 if (session == NULL) {
781 qb_log(LOG_NOTICE, "Failed to init SNMP session.");
782 return ;
783 }
784
785 trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
786 if (!trap_pdu) {
787 qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
788 return ;
789 }
790
791 /* send uptime */
792 snprintf (csysuptime, CS_TIMESTAMP_STR_LEN, "%ld", now);
793 snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
794 snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_NODE);
795
796 /* Add extries to the trap */
797 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
798 add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
799 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_ADDR, (void*)ip, strlen (ip));
800 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_STATUS, (void*)state, strlen (state));
801
802 /* Send and cleanup */
803 ret = snmp_send (session, trap_pdu);
804 if (ret == 0) {
805 /* error */
806 qb_log(LOG_ERR, "Could not send SNMP trap");
807 snmp_free_pdu (trap_pdu);
808 }
809 }
810
811 static void
_cs_snmp_node_quorum_event(char * nodename,uint32_t nodeid,const char * state)812 _cs_snmp_node_quorum_event(char *nodename, uint32_t nodeid,
813 const char *state)
814 {
815 int ret;
816 char csysuptime[20];
817 static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
818 static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
819 time_t now = time (NULL);
820
821 netsnmp_pdu *trap_pdu;
822 netsnmp_session *session = snmp_init (snmp_manager);
823 if (session == NULL) {
824 qb_log(LOG_NOTICE, "Failed to init SNMP session.");
825 return ;
826 }
827
828 trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
829 if (!trap_pdu) {
830 qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
831 return ;
832 }
833
834 /* send uptime */
835 sprintf (csysuptime, "%ld", now);
836 snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
837 snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_QUORUM);
838
839 /* Add extries to the trap */
840 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
841 add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
842 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_QUORUM, (void*)state, strlen (state));
843
844 /* Send and cleanup */
845 ret = snmp_send (session, trap_pdu);
846 if (ret == 0) {
847 /* error */
848 qb_log(LOG_ERR, "Could not send SNMP trap");
849 snmp_free_pdu (trap_pdu);
850 }
851 }
852
853 static void
_cs_snmp_rrp_faulty_event(char * nodename,uint32_t nodeid,uint32_t iface_no,const char * state)854 _cs_snmp_rrp_faulty_event(char *nodename, uint32_t nodeid,
855 uint32_t iface_no, const char *state)
856 {
857 int ret;
858 char csysuptime[20];
859 static oid snmptrap_oid[] = { 1,3,6,1,6,3,1,1,4,1,0 };
860 static oid sysuptime_oid[] = { 1,3,6,1,2,1,1,3,0 };
861 time_t now = time (NULL);
862
863 netsnmp_pdu *trap_pdu;
864 netsnmp_session *session = snmp_init (snmp_manager);
865 if (session == NULL) {
866 qb_log(LOG_NOTICE, "Failed to init SNMP session.");
867 return ;
868 }
869
870 trap_pdu = snmp_pdu_create (SNMP_MSG_TRAP2);
871 if (!trap_pdu) {
872 qb_log(LOG_NOTICE, "Failed to create SNMP notification.");
873 return ;
874 }
875
876 /* send uptime */
877 sprintf (csysuptime, "%ld", now);
878 snmp_add_var (trap_pdu, sysuptime_oid, sizeof (sysuptime_oid) / sizeof (oid), 't', csysuptime);
879 snmp_add_var (trap_pdu, snmptrap_oid, sizeof (snmptrap_oid) / sizeof (oid), 'o', SNMP_OID_TRAPS_RRP);
880
881 /* Add extries to the trap */
882 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_NODE_NAME, (void*)nodename, strlen (nodename));
883 add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_NODE_ID, (void*)&nodeid, sizeof (nodeid));
884 add_field (trap_pdu, ASN_INTEGER, SNMP_OID_OBJECT_RRP_IFACE_NO, (void*)&iface_no, sizeof (iface_no));
885 add_field (trap_pdu, ASN_OCTET_STR, SNMP_OID_OBJECT_RRP_STATUS, (void*)state, strlen (state));
886
887 /* Send and cleanup */
888 ret = snmp_send (session, trap_pdu);
889 if (ret == 0) {
890 /* error */
891 qb_log(LOG_ERR, "Could not send SNMP trap");
892 snmp_free_pdu (trap_pdu);
893 }
894 }
895
896 static void
_cs_snmp_init(void)897 _cs_snmp_init(void)
898 {
899 if (snmp_manager == NULL) {
900 snmp_manager = (char*)local_host;
901 }
902
903 notifiers[num_notifiers].node_membership_fn =
904 _cs_snmp_node_membership_event;
905 notifiers[num_notifiers].node_quorum_fn =
906 _cs_snmp_node_quorum_event;
907 notifiers[num_notifiers].application_connection_fn = NULL;
908 notifiers[num_notifiers].rrp_faulty_fn =
909 _cs_snmp_rrp_faulty_event;
910 num_notifiers++;
911 }
912
913 #endif /* ENABLE_SNMP */
914
915 static void
_cs_syslog_node_membership_event(char * nodename,uint32_t nodeid,char * state,char * ip)916 _cs_syslog_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
917 {
918 qb_log(LOG_NOTICE, "%s[%d] ip:%s %s", nodename, nodeid, ip, state);
919 }
920
921 static void
_cs_syslog_node_quorum_event(char * nodename,uint32_t nodeid,const char * state)922 _cs_syslog_node_quorum_event(char *nodename, uint32_t nodeid, const char *state)
923 {
924 if (strcmp(state, "quorate") == 0) {
925 qb_log(LOG_NOTICE, "%s[%d] is now %s", nodename, nodeid, state);
926 } else {
927 qb_log(LOG_NOTICE, "%s[%d] has lost quorum", nodename, nodeid);
928 }
929 }
930
931 static void
_cs_syslog_application_connection_event(char * nodename,uint32_t nodeid,char * app_name,const char * state)932 _cs_syslog_application_connection_event(char *nodename, uint32_t nodeid, char* app_name, const char *state)
933 {
934 if (strcmp(state, "connected") == 0) {
935 qb_log(LOG_NOTICE, "%s[%d] %s is now %s to corosync", nodename, nodeid, app_name, state);
936 } else {
937 qb_log(LOG_NOTICE, "%s[%d] %s is now %s from corosync", nodename, nodeid, app_name, state);
938 }
939 }
940
941 static void
_cs_syslog_rrp_faulty_event(char * nodename,uint32_t nodeid,uint32_t iface_no,const char * state)942 _cs_syslog_rrp_faulty_event(char *nodename, uint32_t nodeid, uint32_t iface_no, const char *state)
943 {
944 qb_log(LOG_NOTICE, "%s[%d] interface %u is now %s", nodename, nodeid, iface_no, state);
945 }
946
947 static void
_cs_node_membership_event(char * nodename,uint32_t nodeid,char * state,char * ip)948 _cs_node_membership_event(char *nodename, uint32_t nodeid, char *state, char* ip)
949 {
950 int i;
951
952 for (i = 0; i < num_notifiers; i++) {
953 if (notifiers[i].node_membership_fn) {
954 notifiers[i].node_membership_fn(nodename, nodeid, state, ip);
955 }
956 }
957 }
958
959 static void
_cs_local_node_info_get(char ** nodename,uint32_t * nodeid)960 _cs_local_node_info_get(char **nodename, uint32_t *nodeid)
961 {
962 cs_error_t rc;
963 corosync_cfg_handle_t cfg_handle;
964
965 if (g_local_nodeid == 0) {
966 rc = corosync_cfg_initialize(&cfg_handle, NULL);
967 if (rc != CS_OK) {
968 syslog (LOG_ERR, "Failed to initialize the cfg API. Error %d\n", rc);
969 exit (EXIT_FAILURE);
970 }
971
972 rc = corosync_cfg_local_get (cfg_handle, &g_local_nodeid);
973 corosync_cfg_finalize(cfg_handle);
974 if (rc != CS_OK) {
975 g_local_nodeid = 0;
976 strncpy(local_nodename, "localhost", sizeof (local_nodename));
977 local_nodename[sizeof (local_nodename) - 1] = '\0';
978 } else {
979 gethostname(local_nodename, CS_MAX_NAME_LENGTH);
980 }
981 }
982 *nodeid = g_local_nodeid;
983 *nodename = local_nodename;
984 }
985
986 static void
_cs_node_quorum_event(const char * state)987 _cs_node_quorum_event(const char *state)
988 {
989 int i;
990 char *nodename;
991 uint32_t nodeid;
992
993 _cs_local_node_info_get(&nodename, &nodeid);
994
995 for (i = 0; i < num_notifiers; i++) {
996 if (notifiers[i].node_quorum_fn) {
997 notifiers[i].node_quorum_fn(nodename, nodeid, state);
998 }
999 }
1000 }
1001
1002 static void
_cs_application_connection_event(char * app_name,const char * state)1003 _cs_application_connection_event(char *app_name, const char *state)
1004 {
1005 int i;
1006 char *nodename;
1007 uint32_t nodeid;
1008
1009 _cs_local_node_info_get(&nodename, &nodeid);
1010
1011 for (i = 0; i < num_notifiers; i++) {
1012 if (notifiers[i].application_connection_fn) {
1013 notifiers[i].application_connection_fn(nodename, nodeid, app_name, state);
1014 }
1015 }
1016 }
1017
1018 static void
_cs_rrp_faulty_event(uint32_t iface_no,const char * state)1019 _cs_rrp_faulty_event(uint32_t iface_no, const char *state)
1020 {
1021 int i;
1022 char *nodename;
1023 uint32_t nodeid;
1024
1025 _cs_local_node_info_get(&nodename, &nodeid);
1026
1027 for (i = 0; i < num_notifiers; i++) {
1028 if (notifiers[i].rrp_faulty_fn) {
1029 notifiers[i].rrp_faulty_fn(nodename, nodeid, iface_no, state);
1030 }
1031 }
1032 }
1033
1034 static int32_t
sig_exit_handler(int32_t num,void * data)1035 sig_exit_handler(int32_t num, void *data)
1036 {
1037 qb_loop_stop(main_loop);
1038 return 0;
1039 }
1040
1041 static void
_cs_cmap_init(void)1042 _cs_cmap_init(void)
1043 {
1044 cs_error_t rc;
1045 int cmap_fd = 0;
1046
1047 rc = cmap_initialize (&cmap_handle);
1048 if (rc != CS_OK) {
1049 qb_log(LOG_ERR, "Failed to initialize the cmap API. Error %d", rc);
1050 exit (EXIT_FAILURE);
1051 }
1052 cmap_fd_get(cmap_handle, &cmap_fd);
1053
1054 qb_loop_poll_add(main_loop, QB_LOOP_MED, cmap_fd, POLLIN|POLLNVAL, NULL,
1055 _cs_cmap_dispatch);
1056
1057 rc = cmap_track_add(cmap_handle, "runtime.connections.",
1058 CMAP_TRACK_ADD | CMAP_TRACK_DELETE | CMAP_TRACK_PREFIX,
1059 _cs_cmap_connections_key_changed,
1060 NULL,
1061 &cmap_track_handle_connections_key_changed);
1062 if (rc != CS_OK) {
1063 qb_log(LOG_ERR,
1064 "Failed to track the connections key. Error %d", rc);
1065 exit (EXIT_FAILURE);
1066 }
1067
1068 rc = cmap_track_add(cmap_handle, "runtime.totem.pg.mrp.srp.members.",
1069 CMAP_TRACK_ADD | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
1070 _cs_cmap_members_key_changed,
1071 NULL,
1072 &cmap_track_handle_members_key_changed);
1073 if (rc != CS_OK) {
1074 qb_log(LOG_ERR,
1075 "Failed to track the members key. Error %d", rc);
1076 exit (EXIT_FAILURE);
1077 }
1078 rc = cmap_track_add(cmap_handle, "runtime.totem.pg.mrp.rrp.",
1079 CMAP_TRACK_ADD | CMAP_TRACK_MODIFY | CMAP_TRACK_PREFIX,
1080 _cs_cmap_rrp_faulty_key_changed,
1081 NULL,
1082 &cmap_track_handle_rrp_faulty_key_changed);
1083 if (rc != CS_OK) {
1084 qb_log(LOG_ERR,
1085 "Failed to track the rrp key. Error %d", rc);
1086 exit (EXIT_FAILURE);
1087 }
1088 }
1089
1090 static void
_cs_cmap_finalize(void)1091 _cs_cmap_finalize(void)
1092 {
1093 cmap_track_delete(cmap_handle, cmap_track_handle_connections_key_changed);
1094 cmap_track_delete(cmap_handle, cmap_track_handle_members_key_changed);
1095 cmap_track_delete(cmap_handle, cmap_track_handle_rrp_faulty_key_changed);
1096 cmap_finalize (cmap_handle);
1097 }
1098
1099 static void
_cs_check_config(void)1100 _cs_check_config(void)
1101 {
1102 if (conf[CS_NTF_LOG] == QB_FALSE &&
1103 conf[CS_NTF_STDOUT] == QB_FALSE &&
1104 conf[CS_NTF_SNMP] == QB_FALSE &&
1105 conf[CS_NTF_DBUS] == QB_FALSE) {
1106 qb_log(LOG_ERR, "no event type enabled, see corosync-notifyd -h, exiting.");
1107 exit(EXIT_FAILURE);
1108 }
1109
1110 #ifndef ENABLE_SNMP
1111 if (conf[CS_NTF_SNMP]) {
1112 qb_log(LOG_ERR, "Not compiled with SNMP support enabled, exiting.");
1113 exit(EXIT_FAILURE);
1114 }
1115 #endif
1116 #ifndef HAVE_DBUS
1117 if (conf[CS_NTF_DBUS]) {
1118 qb_log(LOG_ERR, "Not compiled with DBus support enabled, exiting.");
1119 exit(EXIT_FAILURE);
1120 }
1121 #endif
1122
1123 if (conf[CS_NTF_STDOUT] && !conf[CS_NTF_FG]) {
1124 qb_log(LOG_ERR, "configured to print to stdout and run in the background, exiting");
1125 exit(EXIT_FAILURE);
1126 }
1127 if (conf[CS_NTF_SNMP] && conf[CS_NTF_DBUS]) {
1128 qb_log(LOG_ERR, "configured to send snmp traps and dbus signals - are you sure?.");
1129 }
1130 }
1131
1132 static void
_cs_usage(void)1133 _cs_usage(void)
1134 {
1135 fprintf(stderr, "usage:\n"\
1136 " -c : SNMP Community name.\n"\
1137 " -f : Start application in foreground.\n"\
1138 " -l : Log all events.\n"\
1139 " -o : Print events to stdout (turns on -l).\n"\
1140 " -s : Send SNMP traps on all events.\n"\
1141 " -m : Set the SNMP Manager IP address (defaults to localhost).\n"\
1142 " -n : No reverse DNS lookup on cmap member change events.\n"\
1143 " -d : Send DBUS signals on all events.\n"\
1144 " -h : Print this help.\n\n");
1145 }
1146
1147 int
main(int argc,char * argv[])1148 main(int argc, char *argv[])
1149 {
1150 int ch;
1151
1152 conf[CS_NTF_FG] = QB_FALSE;
1153 conf[CS_NTF_LOG] = QB_FALSE;
1154 conf[CS_NTF_STDOUT] = QB_FALSE;
1155 conf[CS_NTF_SNMP] = QB_FALSE;
1156 conf[CS_NTF_DBUS] = QB_FALSE;
1157
1158 while ((ch = getopt (argc, argv, "c:floshdnm:")) != EOF) {
1159 switch (ch) {
1160 case 'c':
1161 strncpy(snmp_community_buf, optarg, sizeof (snmp_community_buf));
1162 snmp_community_buf[sizeof (snmp_community_buf) - 1] = '\0';
1163 snmp_community = snmp_community_buf;
1164 break;
1165 case 'f':
1166 conf[CS_NTF_FG] = QB_TRUE;
1167 break;
1168 case 'l':
1169 conf[CS_NTF_LOG] = QB_TRUE;
1170 break;
1171 case 'm':
1172 conf[CS_NTF_SNMP] = QB_TRUE;
1173 strncpy(snmp_manager_buf, optarg, sizeof (snmp_manager_buf));
1174 snmp_manager_buf[sizeof (snmp_manager_buf) - 1] = '\0';
1175 snmp_manager = snmp_manager_buf;
1176 break;
1177 case 'n':
1178 conf[CS_NTF_NODNS] = QB_TRUE;
1179 break;
1180 case 'o':
1181 conf[CS_NTF_LOG] = QB_TRUE;
1182 conf[CS_NTF_STDOUT] = QB_TRUE;
1183 break;
1184 case 's':
1185 conf[CS_NTF_SNMP] = QB_TRUE;
1186 break;
1187 case 'd':
1188 conf[CS_NTF_DBUS] = QB_TRUE;
1189 break;
1190 case 'h':
1191 default:
1192 _cs_usage();
1193 return EXIT_FAILURE;
1194 }
1195 }
1196
1197 qb_log_init("notifyd", LOG_DAEMON, LOG_INFO);
1198
1199 if (conf[CS_NTF_STDOUT]) {
1200 qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
1201 QB_LOG_FILTER_FILE, "*", LOG_DEBUG);
1202 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, conf[CS_NTF_STDOUT]);
1203 }
1204 _cs_check_config();
1205
1206 if (!conf[CS_NTF_FG]) {
1207 if (daemon(0, 0) < 0)
1208 {
1209 perror("daemon() failed");
1210 return EXIT_FAILURE;
1211 }
1212 }
1213
1214 num_notifiers = 0;
1215 if (conf[CS_NTF_LOG]) {
1216 notifiers[num_notifiers].node_membership_fn =
1217 _cs_syslog_node_membership_event;
1218 notifiers[num_notifiers].node_quorum_fn =
1219 _cs_syslog_node_quorum_event;
1220 notifiers[num_notifiers].application_connection_fn =
1221 _cs_syslog_application_connection_event;
1222 notifiers[num_notifiers].rrp_faulty_fn =
1223 _cs_syslog_rrp_faulty_event;
1224 num_notifiers++;
1225 }
1226
1227 main_loop = qb_loop_create();
1228
1229 _cs_cmap_init();
1230 _cs_quorum_init();
1231
1232 #ifdef HAVE_DBUS
1233 if (conf[CS_NTF_DBUS]) {
1234 _cs_dbus_init();
1235 }
1236 #endif /* HAVE_DBUS */
1237
1238 #ifdef ENABLE_SNMP
1239 if (conf[CS_NTF_SNMP]) {
1240 _cs_snmp_init();
1241 }
1242 #endif /* ENABLE_SNMP */
1243
1244 qb_loop_signal_add(main_loop,
1245 QB_LOOP_HIGH,
1246 SIGINT,
1247 NULL,
1248 sig_exit_handler,
1249 NULL);
1250 qb_loop_signal_add(main_loop,
1251 QB_LOOP_HIGH,
1252 SIGQUIT,
1253 NULL,
1254 sig_exit_handler,
1255 NULL);
1256 qb_loop_signal_add(main_loop,
1257 QB_LOOP_HIGH,
1258 SIGTERM,
1259 NULL,
1260 sig_exit_handler,
1261 NULL);
1262
1263 qb_loop_run(main_loop);
1264
1265 #ifdef HAVE_DBUS
1266 if (conf[CS_NTF_DBUS]) {
1267 _cs_dbus_release();
1268 }
1269 #endif /* HAVE_DBUS */
1270
1271 _cs_quorum_finalize();
1272 _cs_cmap_finalize();
1273
1274 return (exit_code);
1275 }
1276
1277