diff --git a/crm/admin/crmadmin.c b/crm/admin/crmadmin.c index ca4db08f6a..bd8c57d990 100644 --- a/crm/admin/crmadmin.c +++ b/crm/admin/crmadmin.c @@ -1,884 +1,884 @@ -/* $Id: crmadmin.c,v 1.14 2004/12/05 16:30:55 andrew Exp $ */ +/* $Id: crmadmin.c,v 1.15 2004/12/10 20:03:20 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int message_timer_id = -1; int message_timeout_ms = 30*1000; GMainLoop *mainloop = NULL; IPC_Channel *crmd_channel = NULL; char *admin_uuid = NULL; void usage(const char *cmd, int exit_status); ll_cluster_t *do_init(void); int do_work(ll_cluster_t * hb_cluster); gboolean admin_msg_callback(IPC_Channel * source_data, void *private_data); char *pluralSection(const char *a_section); xmlNodePtr handleCibMod(void); int do_find_resource(const char *rsc, xmlNodePtr xml_node); int do_find_resource_list(xmlNodePtr xml_node); int do_find_node_list(xmlNodePtr xml_node); gboolean admin_message_timeout(gpointer data); gboolean is_node_online(xmlNodePtr node_state); enum debug { debug_none, debug_dec, debug_inc }; gboolean BE_VERBOSE = FALSE; int expected_responses = 1; gboolean DO_HEALTH = FALSE; gboolean DO_RESET = FALSE; gboolean DO_RESOURCE = FALSE; gboolean DO_ELECT_DC = FALSE; gboolean DO_WHOIS_DC = FALSE; gboolean DO_NODE_LIST = FALSE; gboolean BE_SILENT = FALSE; gboolean DO_RESOURCE_LIST = FALSE; gboolean DO_OPTION = FALSE; enum debug DO_DEBUG = debug_none; xmlNodePtr msg_options = NULL; const char *admin_verbose = XML_BOOLEAN_FALSE; char *id = NULL; char *this_msg_reference = NULL; char *disconnect = NULL; char *dest_node = NULL; char *rsc_name = NULL; char *crm_option = NULL; int operation_status = 0; const char *sys_to = NULL; const char *crm_system_name = "crmadmin"; #define OPTARGS "V?K:S:HE:DW:d:i:RNst:o:" int main(int argc, char **argv) { int option_index = 0; int argerr = 0; int flag; ll_cluster_t *hb_cluster = NULL; int level = 0; static struct option long_options[] = { /* Top-level Options */ {"verbose", 0, 0, 'V'}, {"help", 0, 0, '?'}, {"silent", 0, 0, 's'}, {"reference", 1, 0, 0}, {"timeout", 1, 0, 't'}, /* daemon options */ {"kill", 1, 0, 'K'}, /* stop a node */ {"crm_debug_inc", 1, 0, 'i'}, {"crm_debug_dec", 1, 0, 'd'}, {"status", 1, 0, 'S'}, {"health", 0, 0, 'H'}, {"election", 0, 0, 'E'}, {"dc_lookup", 0, 0, 'D'}, {"resources", 0, 0, 'R'}, {"nodes", 0, 0, 'N'}, {"whereis", 1, 0, 'W'}, {"option", 1, 0, 'o'}, {0, 0, 0, 0} }; /* Redirect messages from glib functions to our handler */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... */ g_log_set_always_fatal((GLogLevelFlags)0); crm_system_name = basename(argv[0]); cl_log_set_entity(crm_system_name); cl_log_set_facility(LOG_USER); if(argc < 2) { usage(crm_system_name, LSB_EXIT_EINVAL); } while (1) { flag = getopt_long(argc, argv, OPTARGS, long_options, &option_index); if (flag == -1) break; switch(flag) { case 0: printf("option %s", long_options[option_index].name); if (optarg) printf(" with arg %s", optarg); printf("\n"); if (strcmp("reference", long_options[option_index].name) == 0) { this_msg_reference = crm_strdup(optarg); } else { printf( "?? Long option (--%s) is not yet properly supported ??\n", long_options[option_index].name); ++argerr; } break; /* a sample test for multiple instance if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); */ case 'V': level = get_crm_log_level(); BE_VERBOSE = TRUE; admin_verbose = XML_BOOLEAN_TRUE; cl_log_enable_stderr(TRUE); set_crm_log_level(level+1); break; case 't': message_timeout_ms = atoi(optarg); if(message_timeout_ms < 1) { message_timeout_ms = 30*1000; } break; case '?': usage(crm_system_name, LSB_EXIT_OK); break; case 'D': DO_WHOIS_DC = TRUE; break; case 'W': DO_RESOURCE = TRUE; crm_verbose("Option %c => %s", flag, optarg); rsc_name = crm_strdup(optarg); break; case 'K': DO_RESET = TRUE; crm_verbose("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'o': DO_OPTION = TRUE; crm_verbose("Option %c => %s", flag, optarg); crm_option = crm_strdup(optarg); break; case 's': BE_SILENT = TRUE; break; case 'i': DO_DEBUG = debug_inc; crm_verbose("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'd': DO_DEBUG = debug_dec; crm_verbose("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'S': DO_HEALTH = TRUE; crm_verbose("Option %c => %s", flag, optarg); dest_node = crm_strdup(optarg); break; case 'E': DO_ELECT_DC = TRUE; break; case 'N': DO_NODE_LIST = TRUE; break; case 'R': DO_RESOURCE_LIST = TRUE; break; case 'H': DO_HEALTH = TRUE; break; default: printf("Argument code 0%o (%c) is not (?yet?) supported\n", flag, flag); ++argerr; break; } } if (optind < argc) { printf("non-option ARGV-elements: "); while (optind < argc) printf("%s ", argv[optind++]); printf("\n"); } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name, LSB_EXIT_GENERIC); } hb_cluster = do_init(); if (hb_cluster != NULL) { int res = do_work(hb_cluster); if (res > 0) { /* wait for the reply by creating a mainloop and running it until * the callbacks are invoked... */ mainloop = g_main_new(FALSE); crm_verbose("%s waiting for reply from the local CRM", crm_system_name); message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); g_main_run(mainloop); return_to_orig_privs(); } else if(res == 0) { crm_verbose("%s: no reply expected", crm_system_name); } else { crm_err("No message to send"); operation_status = -1; } } else { crm_err("Init failed, could not perform requested operations"); operation_status = -2; } crm_verbose("%s exiting normally", crm_system_name); return operation_status; } int do_work(ll_cluster_t * hb_cluster) { int ret = 1; /* construct the request */ xmlNodePtr msg_data = NULL; gboolean all_is_good = TRUE; msg_options = create_xml_node(NULL, XML_TAG_OPTIONS); set_xml_property_copy(msg_options, XML_ATTR_VERBOSE, admin_verbose); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); if (DO_HEALTH == TRUE) { crm_verbose("Querying the system"); sys_to = CRM_SYSTEM_DC; if (dest_node != NULL) { sys_to = CRM_SYSTEM_CRMD; if (BE_VERBOSE) { expected_responses = -1;/* wait until timeout instead */ } set_xml_property_copy( msg_options, XML_ATTR_OP, CRM_OP_PING); set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); } else { crm_info("Cluster-wide health not available yet"); all_is_good = FALSE; } } else if(DO_OPTION) { char *name = NULL; char *value = NULL; xmlNodePtr xml_option = create_xml_node(NULL, XML_CIB_TAG_NVPAIR); sys_to = CRM_SYSTEM_DCIB; set_xml_property_copy( msg_options, XML_ATTR_OP, CRM_OP_CIB_UPDATE); set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); if(decodeNVpair(crm_option, '=', &name, &value) == FALSE) { crm_err("%s needs to be of the form =", crm_option); all_is_good = FALSE; } else { set_xml_property_copy( xml_option, XML_NVPAIR_ATTR_NAME, name); set_xml_property_copy( xml_option, XML_NVPAIR_ATTR_VALUE, value); msg_data = create_cib_fragment(xml_option, NULL); free_xml(xml_option); crm_free(name); crm_free(value); } } else if(DO_ELECT_DC) { /* tell the local node to initiate an election */ sys_to = CRM_SYSTEM_CRMD; set_xml_property_copy( msg_options, XML_ATTR_OP, CRM_OP_VOTE); set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; ret = 0; /* no return message */ } else if(DO_WHOIS_DC) { sys_to = CRM_SYSTEM_DC; set_xml_property_copy( msg_options, XML_ATTR_OP, CRM_OP_PING); set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); dest_node = NULL; } else if(DO_RESOURCE) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OP_CIB_QUERY); set_xml_property_copy( msg_options, XML_ATTR_FILTER_TYPE, XML_CIB_TAG_STATUS); sys_to = CRM_SYSTEM_CIB; } else if(DO_RESOURCE_LIST) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OP_CIB_QUERY); set_xml_property_copy( msg_options, XML_ATTR_FILTER_TYPE, XML_CIB_TAG_RESOURCES); sys_to = CRM_SYSTEM_CIB; } else if(DO_NODE_LIST) { set_xml_property_copy(msg_options, XML_ATTR_OP, CRM_OP_CIB_QUERY); set_xml_property_copy( msg_options, XML_ATTR_FILTER_TYPE, XML_CIB_TAG_NODES); sys_to = CRM_SYSTEM_CIB; } else if(DO_RESET) { /* tell dest_node to initiate the shutdown proceedure * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; set_xml_property_copy( msg_options, XML_ATTR_OP, "init_shutdown"); set_xml_property_copy( msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_inc) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; set_xml_property_copy(msg_options, XML_ATTR_OP, "debug_inc"); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else if(DO_DEBUG == debug_dec) { /* tell dest_node to increase its debug level * * if dest_node is NULL, the request will be sent to the * local node */ sys_to = CRM_SYSTEM_CRMD; set_xml_property_copy(msg_options, XML_ATTR_OP, "debug_dec"); set_xml_property_copy(msg_options, XML_ATTR_TIMEOUT, "0"); ret = 0; /* no return message */ } else { crm_err("Unknown options"); all_is_good = FALSE; } if(all_is_good == FALSE) { crm_err("Creation of request failed. No message to send"); return -1; } /* send it */ if (crmd_channel == NULL) { crm_err("The IPC connection is not valid, cannot send anything"); return -1; } if(sys_to == NULL) { if (dest_node != NULL) sys_to = CRM_SYSTEM_CRMD; else sys_to = CRM_SYSTEM_DC; } send_ipc_request( crmd_channel, msg_options, msg_data, dest_node, sys_to, crm_system_name, admin_uuid, this_msg_reference); return ret; } ll_cluster_t * do_init(void) { int facility; ll_cluster_t *hb_cluster = NULL; /* docs say only do this once, but in their code they do it every time! */ xmlInitParser (); /* change the logging facility to the one used by heartbeat daemon */ hb_cluster = ll_cluster_new("heartbeat"); crm_verbose("Switching to Heartbeat logger"); if (( facility = hb_cluster->llc_ops->get_logfacility(hb_cluster)) > 0) { cl_log_set_facility(facility); } crm_malloc(admin_uuid, sizeof(char) * 11); if(admin_uuid != NULL) { snprintf(admin_uuid, 10, "%d", getpid()); admin_uuid[10] = '\0'; } - crmd_channel = init_client_ipc_comms( - CRM_SYSTEM_CRMD, admin_msg_callback, NULL); + init_client_ipc_comms( + CRM_SYSTEM_CRMD, admin_msg_callback, NULL, &crmd_channel); if(crmd_channel != NULL) { send_hello_message( crmd_channel, admin_uuid, crm_system_name,"0", "1"); return hb_cluster; } return NULL; } gboolean admin_msg_callback(IPC_Channel * server, void *private_data) { int lpc = 0; IPC_Message *msg = NULL; gboolean hack_return_good = TRUE; static int received_responses = 0; char *filename; int filename_len = 0; const char *result = NULL; xmlNodePtr options = NULL; xmlNodePtr xml_root_node = NULL; char *buffer = NULL; g_source_remove(message_timer_id); while (server->ch_status != IPC_DISCONNECT && server->ops->is_message_pending(server) == TRUE) { if (server->ops->recv(server, &msg) != IPC_OK) { perror("Receive failure:"); return !hack_return_good; } if (msg == NULL) { crm_trace("No message this time"); continue; } lpc++; buffer =(char *) msg->msg_body; crm_verbose("Got xml [text=%s]", buffer); xml_root_node = find_xml_in_ipcmessage(msg, TRUE); if (xml_root_node == NULL) { crm_info( "XML in IPC message was not valid... " "discarding."); continue; } else if (validate_crm_message(xml_root_node, crm_system_name, admin_uuid, "response") == FALSE) { crm_info( "Message was not a CRM response. Discarding."); continue; } options = find_xml_node(xml_root_node, XML_TAG_OPTIONS); result = xmlGetProp(options, XML_ATTR_RESULT); if(result == NULL || strcmp(result, "ok") == 0) { result = "pass"; } else { result = "fail"; } received_responses++; if(DO_HEALTH) { xmlNodePtr ping = find_xml_node( xml_root_node, XML_CRM_TAG_PING); const char *state = xmlGetProp(ping, "crmd_state"); printf("Status of %s@%s: %s (%s)\n", xmlGetProp(ping, XML_PING_ATTR_SYSFROM), xmlGetProp(xml_root_node, XML_ATTR_HOSTFROM), state, xmlGetProp(ping, XML_PING_ATTR_STATUS)); if(BE_SILENT && state != NULL) { fprintf(stderr, "%s\n", state); } } else if(DO_RESOURCE) { do_find_resource(rsc_name, xml_root_node); } else if(DO_RESOURCE_LIST) { do_find_resource_list(xml_root_node); } else if(DO_NODE_LIST) { do_find_node_list(xml_root_node); } else if(DO_WHOIS_DC) { const char *dc = xmlGetProp( xml_root_node, XML_ATTR_HOSTFROM); printf("Designated Controller is: %s\n", dc); if(BE_SILENT && dc != NULL) { fprintf(stderr, "%s\n", dc); } } if (this_msg_reference != NULL) { /* in testing mode... */ /* 31 = "test-_.xml" + an_int_as_string + '\0' */ filename_len = 31 + strlen(this_msg_reference); crm_malloc(filename, sizeof(char) * filename_len); if(filename != NULL) { sprintf(filename, "%s-%s_%d.xml", result, this_msg_reference, received_responses); filename[filename_len - 1] = '\0'; if (xmlSaveFormatFile( filename, xml_root_node->doc, 1) < 0) { crm_crit("Could not save response to" " %s_%s_%d.xml", this_msg_reference, result, received_responses); } } } } if (server->ch_status == IPC_DISCONNECT) { crm_verbose("admin_msg_callback: received HUP"); return !hack_return_good; } if (received_responses >= expected_responses) { crm_verbose( "Recieved expected number (%d) of messages from Heartbeat." " Exiting normally.", expected_responses); g_main_quit(mainloop); return !hack_return_good; } message_timer_id = Gmain_timeout_add( message_timeout_ms, admin_message_timeout, NULL); return hack_return_good; } gboolean admin_message_timeout(gpointer data) { fprintf(stderr, "No messages received in %d seconds.. aborting\n", (int)message_timeout_ms/1000); crm_err("No messages received in %d seconds", (int)message_timeout_ms/1000); g_main_quit(mainloop); return FALSE; } int do_find_resource(const char *rsc, xmlNodePtr xml_node) { int found = 0; const char *path[] = { XML_TAG_FRAGMENT, XML_TAG_CIB, XML_CIB_TAG_STATUS, XML_CIB_TAG_STATE }; const char *path2[] = { XML_CIB_TAG_LRM, XML_LRM_TAG_RESOURCES, XML_LRM_TAG_RESOURCE }; xmlNodePtr nodestates = find_xml_node_nested( xml_node, path, DIMOF(path)); while(nodestates != NULL) { xmlNodePtr rscstates = NULL; xmlNodePtr a_node = nodestates; nodestates = nodestates->next; if(is_node_online(a_node) == FALSE) { crm_debug("Skipping offline node: %s", xmlGetProp(a_node, XML_ATTR_ID)); continue; } rscstates = find_xml_node_nested(a_node, path2, DIMOF(path2)); while(rscstates != NULL) { const char *id = xmlGetProp(rscstates,XML_ATTR_ID); const char *target = xmlGetProp(rscstates,XML_LRM_ATTR_TARGET); const char *last_op = xmlGetProp(rscstates,XML_LRM_ATTR_LASTOP); const char *op_code = xmlGetProp(rscstates,XML_LRM_ATTR_OPSTATUS); rscstates = rscstates->next; crm_debug("checking %s:%s for %s", target, id, rsc); if(safe_str_neq(rsc, id)){ crm_trace("no match"); continue; } if(safe_str_eq("stop", last_op)) { crm_debug("resource %s is stopped on: %s\n", rsc, target); } else if(safe_str_neq(op_code, "0")) { crm_debug("resource %s is failed on: %s\n", rsc, target); } else { crm_debug("resource %s is running on: %s\n", rsc, target); printf("resource %s is running on: %s\n", rsc, target); if(BE_SILENT) { fprintf(stderr, "%s ", target); } found++; } } if(BE_SILENT) { fprintf(stderr, "\n"); } } if(found == 0) { printf("resource %s is NOT running\n", rsc); } return found; } gboolean is_node_online(xmlNodePtr node_state) { const char *uname = xmlGetProp(node_state,XML_ATTR_UNAME); const char *join_state = xmlGetProp(node_state,XML_CIB_ATTR_JOINSTATE); const char *crm_state = xmlGetProp(node_state,XML_CIB_ATTR_CRMDSTATE); const char *ha_state = xmlGetProp(node_state,XML_CIB_ATTR_HASTATE); const char *ccm_state = xmlGetProp(node_state,XML_CIB_ATTR_INCCM); if(safe_str_eq(join_state, CRMD_JOINSTATE_MEMBER) && safe_str_eq(ha_state, ACTIVESTATUS) && safe_str_eq(ccm_state, XML_BOOLEAN_YES) && safe_str_eq(crm_state, ONLINESTATUS)) { crm_debug("Node %s is online", uname); return TRUE; } crm_debug("Node %s: %s %s %s", uname, join_state, ccm_state, crm_state); crm_debug("Node %s is offline", uname); return FALSE; } int do_find_resource_list(xmlNodePtr xml_node) { int found = 0; const char *path[] = { XML_TAG_FRAGMENT, XML_TAG_CIB, XML_CIB_TAG_RESOURCES, XML_CIB_TAG_RESOURCE }; xmlNodePtr rscs = find_xml_node_nested( xml_node, path, DIMOF(path)); while(rscs != NULL) { printf("%s resource: %s (%s)\n", xmlGetProp(rscs, "class"), xmlGetProp(rscs, XML_ATTR_ID), xmlGetProp(rscs, XML_ATTR_TYPE)); rscs = rscs->next; found++; } if(found == 0) { printf("NO resources configured\n"); } return found; } int do_find_node_list(xmlNodePtr xml_node) { int found = 0; const char *path[] = { XML_TAG_FRAGMENT, XML_TAG_CIB, XML_CIB_TAG_NODES, XML_CIB_TAG_NODE }; xmlNodePtr nodes = find_xml_node_nested( xml_node, path, DIMOF(path)); while(nodes != NULL) { printf("%s node: %s (%s)\n", xmlGetProp(nodes, XML_ATTR_TYPE), xmlGetProp(nodes, XML_ATTR_UNAME), xmlGetProp(nodes, XML_ATTR_ID)); nodes = nodes->next; found++; } if(found == 0) { printf("NO nodes configured\n"); } return found; } void usage(const char *cmd, int exit_status) { FILE *stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-?vs] [command] [command args]\n", cmd); fprintf(stream, "Options\n"); fprintf(stream, "\t--%s (-%c)\t: " "turn on debug info. additional instances increase verbosity\n", "verbose", 'V'); fprintf(stream, "\t--%s (-%c)\t: be very very quiet\n", "silent", 's'); fprintf(stream, "\t--%s (-%c)\t: this help message\n", "help", '?'); fprintf(stream, "\nCommands\n"); fprintf(stream, "\t--%s (-%c) \t: " "increment the CRMd debug level on \n", "debug_inc",'i'); fprintf(stream, "\t--%s (-%c) \t: " "decrement the CRMd debug level on \n", "debug_dec",'d'); fprintf(stream, "\t--%s (-%c) \t: " "shutdown the CRMd on \n", "kill", 'K'); fprintf(stream, "\t--%s (-%c) \t: " "request the status of \n", "status", 'S'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the status of all nodes\n", "health", 'H'); fprintf(stream, "\t--%s (-%c) \t: " "initiate an election from \n", "election", 'E'); fprintf(stream, "\t--%s (-%c)\t: " "request the uname of the DC\n", "dc_lookup", 'D'); fprintf(stream, "\t--%s (-%c)\t\t: " "request the uname of all member nodes\n", "nodes", 'N'); fprintf(stream, "\t--%s (-%c)\t: " "request the names of all resources\n", "resources", 'R'); fprintf(stream, "\t--%s (-%c) \t: " "request the location of \n", "whereis", 'W'); /* fprintf(stream, "\t--%s (-%c)\t\n", "disconnect", 'D'); */ fflush(stream); exit(exit_status); } diff --git a/crm/common/ipc.c b/crm/common/ipc.c index d3ee974f64..2baffdbd5c 100644 --- a/crm/common/ipc.c +++ b/crm/common/ipc.c @@ -1,474 +1,473 @@ -/* $Id: ipc.c,v 1.13 2004/12/05 16:29:51 andrew Exp $ */ +/* $Id: ipc.c,v 1.14 2004/12/10 20:03:20 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IPC_Message *create_simple_message(char *text, IPC_Channel *ch); gboolean send_ipc_message(IPC_Channel *ipc_client, IPC_Message *msg); static void free_msg_data(IPC_Message *msg); gboolean send_xmlipc_message(IPC_Channel *ipc_client, xmlNodePtr msg) { int log_level = LOG_DEBUG; char *xml_message = NULL; IPC_Message *cib_dump = NULL; gboolean res; xml_message = dump_xml_unformatted(msg); cib_dump = create_simple_message(xml_message, ipc_client); res = send_ipc_message(ipc_client, cib_dump); /* crm_free(xml_message); */ if(res == FALSE) { log_level = LOG_ERR; } do_crm_log(log_level, __FUNCTION__, "Sending IPC message (ref=%s) to %s@%s %s.", xmlGetProp(msg, XML_ATTR_REFERENCE), xmlGetProp(msg, XML_ATTR_SYSTO), xmlGetProp(msg, XML_ATTR_HOSTTO), res?"succeeded":"failed"); return res; } gboolean send_ipc_message(IPC_Channel *ipc_client, IPC_Message *msg) { int lpc = 0; gboolean all_is_good = TRUE; if (msg == NULL) { crm_err("cant send NULL message"); all_is_good = FALSE; } else if (msg->msg_len <= 0) { crm_err("cant send 0 sized message"); all_is_good = FALSE; } else if (msg->msg_len > MAXDATASIZE) { crm_err("cant send msg... too big"); all_is_good = FALSE; } crm_trace("Sending message: %s", crm_str(msg?msg->msg_body:NULL)); crm_verbose("Message is%s valid to send", all_is_good?"":" not"); if (ipc_client == NULL) { all_is_good = FALSE; } crm_verbose("IPC Client is%s set.", all_is_good?"":" not"); if (all_is_good) { while(lpc++ < MAX_IPC_FAIL && ipc_client->ops->send(ipc_client, msg) == IPC_FAIL) { crm_err("ipc channel blocked"); cl_shortsleep(); } } if (lpc == MAX_IPC_FAIL) { crm_err("Could not send IPC, message. Channel is dead."); all_is_good = FALSE; } return all_is_good; } static void free_msg_data(IPC_Message *msg) { crm_free(msg->msg_body); msg->msg_body = NULL; } IPC_Message * create_simple_message(char *text, IPC_Channel *ch) { /* char str[256]; */ IPC_Message *ack_msg = NULL; if (text == NULL) { return NULL; } ack_msg = cl_malloc(sizeof(IPC_Message)); if(ack_msg == NULL) { return NULL; } ack_msg->msg_private = NULL; ack_msg->msg_buf = NULL; ack_msg->msg_ch = ch; ack_msg->msg_body = text; ack_msg->msg_done = free_msg_data; ack_msg->msg_len = strlen(text)+1; return ack_msg; } xmlNodePtr find_xml_in_ipcmessage(IPC_Message *msg, gboolean do_free) { char *buffer = NULL; xmlDocPtr doc; xmlNodePtr root; if (msg == NULL) { crm_trace("IPC Message was empty..."); return NULL; } buffer = (char*)msg->msg_body; doc = xmlParseMemory(buffer, strlen(buffer)); if (do_free) msg->msg_done(msg); if (doc == NULL) { crm_info("IPC Message did not contain an XML buffer..."); return NULL; } root = xmlDocGetRootElement(doc); if (root == NULL) { crm_info("Root node was NULL."); return NULL; } return root; } void default_ipc_connection_destroy(gpointer user_data) { return; } int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)(IPC_Channel *newclient,gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)) { /* the clients wait channel is the other source of events. * This source delivers the clients connection events. * listen to this source at a relatively lower priority. */ char commpath[SOCKET_LEN]; IPC_WaitConnection *wait_ch; sprintf(commpath, WORKING_DIR "/%s", channel_name); wait_ch = wait_channel_init(commpath); if (wait_ch == NULL) { return 1; } G_main_add_IPC_WaitConnection( G_PRIORITY_LOW, wait_ch, NULL, FALSE, channel_client_connect, channel_name, channel_connection_destroy); crm_debug("Listening on: %s", commpath); return 0; } -/* GCHSource* */ -IPC_Channel * +GCHSource* init_client_ipc_comms(const char *channel_name, gboolean (*dispatch)( IPC_Channel* source_data, gpointer user_data), - void *client_data) + void *client_data, IPC_Channel **ch) { - IPC_Channel *ch = NULL; + *ch = NULL; GCHSource *the_source = NULL; void *callback_data = client_data; if(callback_data == NULL) { - callback_data = ch; + callback_data = *ch; } - ch = init_client_ipc_comms_nodispatch(channel_name); + *ch = init_client_ipc_comms_nodispatch(channel_name); - if(ch == NULL) { + if(*ch == NULL) { crm_err("Setup of client connection failed," " not adding channel to mainloop"); return NULL; } if(dispatch == NULL) { crm_warn("No dispatch method specified..." "maybe you meant init_client_ipc_comms_nodispatch()?"); } else { crm_debug("Adding dispatch method to channel"); the_source = G_main_add_IPC_Channel( - G_PRIORITY_LOW, ch, FALSE, dispatch, callback_data, + G_PRIORITY_LOW, *ch, FALSE, dispatch, callback_data, default_ipc_connection_destroy); } - return ch; + return the_source; } IPC_Channel * init_client_ipc_comms_nodispatch(const char *channel_name) { IPC_Channel *ch; GHashTable *attrs; static char path[] = IPC_PATH_ATTR; char *commpath = NULL; int local_socket_len = 2; /* 2 = '/' + '\0' */ local_socket_len += strlen(channel_name); local_socket_len += strlen(WORKING_DIR); crm_malloc(commpath, sizeof(char)*local_socket_len); if(commpath != NULL) { sprintf(commpath, WORKING_DIR "/%s", channel_name); commpath[local_socket_len - 1] = '\0'; crm_debug("Attempting to talk on: %s", commpath); } attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, commpath); ch = ipc_channel_constructor(IPC_ANYTYPE, attrs); g_hash_table_destroy(attrs); if (ch == NULL) { crm_crit("Could not access channel on: %s", commpath); return NULL; } else if (ch->ops->initiate_connection(ch) != IPC_OK) { crm_crit("Could not init comms on: %s", commpath); fprintf(stderr, "Could not init comms on: %s\n", commpath); return NULL; } ch->ops->set_recv_qlen(ch, 100); ch->ops->set_send_qlen(ch, 100); crm_debug("Processing of %s complete", commpath); return ch; } IPC_WaitConnection * wait_channel_init(char daemonsocket[]) { IPC_WaitConnection *wait_ch; mode_t mask; char path[] = IPC_PATH_ATTR; GHashTable * attrs; attrs = g_hash_table_new(g_str_hash,g_str_equal); g_hash_table_insert(attrs, path, daemonsocket); mask = umask(0); wait_ch = ipc_wait_conn_constructor(IPC_ANYTYPE, attrs); if (wait_ch == NULL) { cl_perror("Can't create wait channel of type %s", IPC_ANYTYPE); exit(1); } mask = umask(mask); g_hash_table_destroy(attrs); return wait_ch; } /* * This method adds a copy of xml_response_data */ gboolean send_ipc_request(IPC_Channel *ipc_channel, xmlNodePtr msg_options, xmlNodePtr msg_data, const char *host_to, const char *sys_to, const char *sys_from, const char *uuid_from, const char *crm_msg_reference) { gboolean was_sent = FALSE; xmlNodePtr request = NULL; request = create_request(msg_options, msg_data, host_to, sys_to, sys_from, uuid_from, crm_msg_reference); was_sent = send_xmlipc_message(ipc_channel, request); free_xml(request); return was_sent; } /* * This method adds a copy of xml_response_data */ gboolean send_ipc_reply(IPC_Channel *ipc_channel, xmlNodePtr xml_request, xmlNodePtr xml_response_data) { gboolean was_sent = FALSE; xmlNodePtr reply; reply = create_reply(xml_request, xml_response_data); if (reply != NULL) { was_sent = send_xmlipc_message(ipc_channel, reply); free_xml(reply); } return was_sent; } gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data) { int lpc = 0; char *buffer = NULL; IPC_Message *msg = NULL; gboolean all_is_well = TRUE; xmlNodePtr root_xml_node = NULL; const char *sys_to; const char *type; while(sender->ops->is_message_pending(sender)) { if (sender->ch_status == IPC_DISCONNECT) { /* The message which was pending for us is that * the IPC status is now IPC_DISCONNECT */ break; } if (sender->ops->recv(sender, &msg) != IPC_OK) { perror("Receive failure:"); return !all_is_well; } if (msg == NULL) { crm_err("No message this time"); continue; } lpc++; buffer = (char*)msg->msg_body; root_xml_node = string2xml(buffer); sys_to= xmlGetProp(root_xml_node, XML_ATTR_SYSTO); type = xmlGetProp(root_xml_node, XML_ATTR_MSGTYPE); if (root_xml_node == NULL) { crm_err("Root node was NULL!!"); } else if(sys_to == NULL) { crm_err("Value of %s was NULL!!", XML_ATTR_SYSTO); } else if(type == NULL) { crm_err("Value of %s was NULL!!", XML_ATTR_MSGTYPE); } else { gboolean (*process_function) (xmlNodePtr msg, IPC_Channel *sender) = NULL; process_function = user_data; if(process_function(root_xml_node, sender) == FALSE) { crm_warn("Received a message destined for %s" " by mistake", sys_to); } } free_xml(root_xml_node); root_xml_node = NULL; msg->msg_done(msg); msg = NULL; } /* clean up after a break */ if(msg != NULL) msg->msg_done(msg); if(root_xml_node != NULL) free_xml(root_xml_node); crm_verbose("Processed %d messages", lpc); if (sender->ch_status == IPC_DISCONNECT) { crm_err("The server has left us: Shutting down...NOW"); exit(1); /* shutdown properly later */ return !all_is_well; } return all_is_well; } diff --git a/crm/pengine/main.c b/crm/pengine/main.c index a081aa9f1c..d8b5f7dce4 100644 --- a/crm/pengine/main.c +++ b/crm/pengine/main.c @@ -1,235 +1,235 @@ -/* $Id: main.c,v 1.4 2004/11/24 15:40:17 andrew Exp $ */ +/* $Id: main.c,v 1.5 2004/12/10 20:03:20 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYS_NAME CRM_SYSTEM_PENGINE #define OPTARGS "skrhVc" #define PID_FILE WORKING_DIR "/" SYS_NAME ".pid" #define DAEMON_LOG DEVEL_DIR"/"SYS_NAME".log" #define DAEMON_DEBUG DEVEL_DIR"/"SYS_NAME".debug" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; void usage(const char* cmd, int exit_status); int init_start(void); void pengine_shutdown(int nsig); extern gboolean process_pe_message(xmlNodePtr msg, IPC_Channel *sender); int main(int argc, char ** argv) { gboolean allow_cores = TRUE; int req_restart = FALSE; int req_status = FALSE; int req_stop = FALSE; int argerr = 0; int flag; /* Redirect messages from glib functions to our handler */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... */ g_log_set_always_fatal((GLogLevelFlags)0); cl_log_set_entity(crm_system_name); cl_log_set_facility(LOG_USER); cl_log_set_logfile(DAEMON_LOG); cl_log_set_debugfile(DAEMON_DEBUG); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 's': /* Status */ req_status = TRUE; break; case 'k': /* Stop (kill) */ req_stop = TRUE; break; case 'r': /* Restart */ req_restart = TRUE; break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } } if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ if(allow_cores) { cl_set_corerootdir(DEVEL_DIR); cl_enable_coredumps(1); cl_cdtocoredir(); } if (req_status){ return init_status(PID_FILE, crm_system_name); } if (req_stop){ return init_stop(PID_FILE); } if (req_restart) { init_stop(PID_FILE); } return init_start(); } int init_start(void) { ll_cluster_t* hb_fd = NULL; int facility; IPC_Channel *crm_ch = NULL; #ifdef REALTIME_SUPPORT static int crm_realtime = 1; #endif /* change the logging facility to the one used by heartbeat daemon */ hb_fd = ll_cluster_new("heartbeat"); crm_info("Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } crm_info("Register PID"); register_pid(PID_FILE, FALSE, pengine_shutdown); - crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, - subsystem_msg_dispatch, - (void*)process_pe_message); + init_client_ipc_comms( + CRM_SYSTEM_CRMD, subsystem_msg_dispatch, + (void*)process_pe_message, &crm_ch); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_PENGINE, "0", "1"); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s", crm_system_name); #ifdef REALTIME_SUPPORT if (crm_realtime == 1){ cl_enable_realtime(); }else if (crm_realtime == 0){ cl_disable_realtime(); } cl_make_realtime(SCHED_RR, 5, 64, 64); #endif g_main_run(mainloop); } else { crm_err("Could not connect to the CRMd"); } return_to_orig_privs(); if (unlink(PID_FILE) == 0) { crm_info("[%s] stopped", crm_system_name); } if(crm_ch != NULL) return 0; return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } void pengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, pengine_shutdown); if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); }else{ exit(LSB_EXIT_OK); } } diff --git a/crm/tengine/main.c b/crm/tengine/main.c index 6bd6972d0a..2a1e4debbd 100644 --- a/crm/tengine/main.c +++ b/crm/tengine/main.c @@ -1,239 +1,239 @@ -/* $Id: main.c,v 1.7 2004/11/24 15:39:02 andrew Exp $ */ +/* $Id: main.c,v 1.8 2004/12/10 20:03:20 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define SYS_NAME CRM_SYSTEM_TENGINE #define OPTARGS "skrhVc" #define PID_FILE WORKING_DIR "/" SYS_NAME ".pid" #define DAEMON_LOG DEVEL_DIR"/"SYS_NAME".log" #define DAEMON_DEBUG DEVEL_DIR"/"SYS_NAME".debug" GMainLoop* mainloop = NULL; const char* crm_system_name = SYS_NAME; void usage(const char* cmd, int exit_status); int init_start(void); void tengine_shutdown(int nsig); int main(int argc, char ** argv) { gboolean allow_cores = TRUE; int req_restart = FALSE; int req_status = FALSE; int req_stop = FALSE; int argerr = 0; int flag; /* Redirect messages from glib functions to our handler */ g_log_set_handler(NULL, G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE | G_LOG_LEVEL_INFO | G_LOG_LEVEL_DEBUG | G_LOG_FLAG_RECURSION | G_LOG_FLAG_FATAL, cl_glib_msg_handler, NULL); /* and for good measure... */ g_log_set_always_fatal((GLogLevelFlags)0); cl_log_set_entity(crm_system_name); cl_log_set_facility(LOG_USER); cl_log_set_logfile(DAEMON_LOG); cl_log_set_debugfile(DAEMON_DEBUG); crm_debug("Begining option processing"); while ((flag = getopt(argc, argv, OPTARGS)) != EOF) { switch(flag) { case 'V': alter_debug(DEBUG_INC); break; case 's': /* Status */ req_status = TRUE; break; case 'k': /* Stop (kill) */ req_stop = TRUE; break; case 'r': /* Restart */ req_restart = TRUE; break; case 'h': /* Help message */ usage(crm_system_name, LSB_EXIT_OK); break; case 'c': allow_cores = TRUE; break; default: ++argerr; break; } } crm_debug("Option processing complete"); if (optind > argc) { ++argerr; } if (argerr) { usage(crm_system_name,LSB_EXIT_GENERIC); } /* read local config file */ if(allow_cores) { crm_debug("Enabling coredumps"); cl_set_corerootdir(DEVEL_DIR); cl_enable_coredumps(1); cl_cdtocoredir(); crm_debug("Coredump processing complete"); } if (req_status){ return init_status(PID_FILE, crm_system_name); } if (req_stop){ return init_stop(PID_FILE); } if (req_restart) { init_stop(PID_FILE); } crm_debug("Starting..."); return init_start(); } int init_start(void) { ll_cluster_t* hb_fd = NULL; int facility; #ifdef REALTIME_SUPPORT static int crm_realtime = 1; #endif /* change the logging facility to the one used by heartbeat daemon */ hb_fd = ll_cluster_new("heartbeat"); crm_info("Switching to Heartbeat logger"); if ((facility = hb_fd->llc_ops->get_logfacility(hb_fd))>0) { cl_log_set_facility(facility); } crm_info("Register PID"); register_pid(PID_FILE, FALSE, tengine_shutdown); - crm_ch = init_client_ipc_comms(CRM_SYSTEM_CRMD, - subsystem_msg_dispatch, - (void*)process_te_message); + init_client_ipc_comms( + CRM_SYSTEM_CRMD, subsystem_msg_dispatch, + (void*)process_te_message, &crm_ch); if(crm_ch != NULL) { send_hello_message(crm_ch, "1234", CRM_SYSTEM_TENGINE, "0", "1"); /* Create the mainloop and run it... */ mainloop = g_main_new(FALSE); crm_info("Starting %s", crm_system_name); #ifdef REALTIME_SUPPORT if (crm_realtime == 1){ cl_enable_realtime(); }else if (crm_realtime == 0){ cl_disable_realtime(); } cl_make_realtime(SCHED_RR, 5, 64, 64); #endif g_main_run(mainloop); } else { crm_err("Could not connect to the CRMd"); } return_to_orig_privs(); if (unlink(PID_FILE) == 0) { crm_info("[%s] stopped", crm_system_name); } if(crm_ch != NULL) return 0; return 1; } void usage(const char* cmd, int exit_status) { FILE* stream; stream = exit_status ? stderr : stdout; fprintf(stream, "usage: %s [-srkh]" "[-c configure file]\n", cmd); /* fprintf(stream, "\t-d\tsets debug level\n"); */ /* fprintf(stream, "\t-s\tgets daemon status\n"); */ /* fprintf(stream, "\t-r\trestarts daemon\n"); */ /* fprintf(stream, "\t-k\tstops daemon\n"); */ /* fprintf(stream, "\t-h\thelp message\n"); */ fflush(stream); exit(exit_status); } void tengine_shutdown(int nsig) { static int shuttingdown = 0; CL_SIGNAL(nsig, tengine_shutdown); if (!shuttingdown) { shuttingdown = 1; } if (mainloop != NULL && g_main_is_running(mainloop)) { g_main_quit(mainloop); }else{ exit(LSB_EXIT_OK); } } diff --git a/include/crm/common/ipc.h b/include/crm/common/ipc.h index 492e812b6a..b03fdebf82 100644 --- a/include/crm/common/ipc.h +++ b/include/crm/common/ipc.h @@ -1,66 +1,66 @@ -/* $Id: ipc.h,v 1.4 2004/12/05 16:04:42 andrew Exp $ */ +/* $Id: ipc.h,v 1.5 2004/12/10 20:03:20 andrew Exp $ */ /* * Copyright (C) 2004 Andrew Beekhof * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CRM_COMMON_IPC__H #define CRM_COMMON_IPC__H #include #include #include #include typedef struct crmd_client_s { char *sub_sys; char *uuid; char *table_key; IPC_Channel *client_channel; GCHSource *client_source; } crmd_client_t; extern gboolean send_ipc_message(IPC_Channel *ipc_client, IPC_Message *msg); extern void default_ipc_connection_destroy(gpointer user_data); -extern xmlNodePtr find_xml_in_ipcmessage(IPC_Message *msg, - gboolean do_free); +extern xmlNodePtr find_xml_in_ipcmessage( + IPC_Message *msg, gboolean do_free); -extern gboolean send_xmlipc_message(IPC_Channel *ipc_client, - xmlNodePtr msg); +extern gboolean send_xmlipc_message( + IPC_Channel *ipc_client, xmlNodePtr msg); extern int init_server_ipc_comms( char *channel_name, gboolean (*channel_client_connect)( IPC_Channel *newclient, gpointer user_data), void (*channel_connection_destroy)(gpointer user_data)); -/* extern GCHSource *init_client_ipc_comms( */ -extern IPC_Channel *init_client_ipc_comms( +extern GCHSource *init_client_ipc_comms( const char *channel_name, - gboolean (*dispatch)(IPC_Channel* source_data, gpointer user_data), - void *client_data); + gboolean (*dispatch)( + IPC_Channel* source_data, gpointer user_data), + void *client_data, IPC_Channel **ch); extern IPC_Channel *init_client_ipc_comms_nodispatch(const char *channel_name); extern gboolean subsystem_msg_dispatch(IPC_Channel *sender, void *user_data); extern IPC_WaitConnection *wait_channel_init(char daemonsocket[]); #endif