/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* 61haes_r714 src/43haes/usr/sbin/cluster/clstat/clstat.c 1.49.1.10 */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* Restricted Materials of IBM */ /* */ /* COPYRIGHT International Business Machines Corp. 1990,2013 */ /* All Rights Reserved */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* */ /* IBM_PROLOG_END_TAG */ static char sccsid[] = "@(#)42 1.49.1.10 src/43haes/usr/sbin/cluster/clstat/clstat.c, hacmp.clstat, 61haes_r714 7/2/13 19:39:20"; /* * COMPONENT_NAME: CLSTAT * * FUNCTIONS: TTYmain * HTMLmain * auto_stat * cl_dump_nodemap * compareNetifs * compareNodemap * copyNodemap * find_cluster * get_clstr_rspns * get_cluster_info * get_state * get_substate * HTML_state_color * HTML_substate_color * inter_act_stat * make_filename * fmt_date * resetClustermap * resetNodemap * resetGroupmap * show_commands * sig_handler * term_dumb * usage * * ORIGINS: 27 * * * (C) COPYRIGHT International Business Machines Corp. 1990,1994 * All Rights Reserved * Licensed Materials - Property of IBM * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __LINUX__ #include #include #include #endif #include #include "clinfo.h" #include "utilities_msg.h" #include "clstat.h" /* ILS */ #include #include #define MSGSTR(Num, Str) catgets((nl_catd)get_catd("utilities.cat"), CLSTAT_MSG_SET, Num, Str) #ifndef lint #endif /* Global variables used in clstat */ char *progname; int ONCE=0; int INTERACT=0; int TEST=0; int FORCE=0; int CLUSTERED=0; int CLUSTERNAMED=0; int helpOptionSpecified=0; static int ALLSERVICES=0; int wait_time; int rflag; int nbr_nodes; int nbr_groups; int redisplay = 0; /* this is set in response to a signal from clinfo */ int clinfo_signal = 0; /* Curses terminal data */ char *TERM; char *CR = "", *UP = "", *CE = "", *CL = ""; char tx[1024]; static char stx[1024]; char *stx_ptr = stx; /* The global HTML/CGI mode boolean value. * 1 = HTML/CGI mode * 0 = ASCII mode */ char HTMLmode = 0; /* External decl */ char *tgetstr(); /* Forward decl */ int compareNetifs(); int compareNodemap(); void copyNodemap(); void resetClustermap(); void resetNodemap(); void resetGroupmap(); char *resourceStateStr(struct cl_group *, int); char *resourceStateColor(struct cl_group *, int); void javaGroupInfo(struct cl_group *, struct cl_node *, int); char *nodeArrayStr(struct cl_node*, int *, int); char *resourcePolicyStr(int); caddr_t odmget(char *, char *, int *); static nl_catd get_catd(char *); /* routine to setup signal handler with clinfo */ static int register_with_clinfo(const int, const struct cl_cluster *); static void clstat_sleep(const int); void cl_dump_nodemap(struct cl_node *nm, int num_nodes) { int i,j; const char *ip_string_ptr = NULL; char ip_string[MAXIPLEN+1]; printf(MSGSTR(CLSTAT_DUMP_MAP, "\n\nDumping nodemap for cluster %d\n\n"), nm->cln_clusterid); for (i=0; isa_family) { case AF_INET: ip_string_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)&nm[i].cln_if[j].cli_addr6)->sin_addr, ip_string, sizeof(ip_string)); break; case AF_INET6: ip_string_ptr = inet_ntop(AF_INET6, &((struct sockaddr_in6*)&nm[i].cln_if[j].cli_addr6)->sin6_addr, ip_string, sizeof(ip_string)); break; } /* ip_string = inet_ntoa (nm[i].cln_if[j].cli_addr.sin_addr.s_addr); */ printf(MSGSTR(CLSTAT_MSG_9, " addr = %s\n"), (ip_string_ptr == NULL) ? MSGSTR(CLSTAT_CONVERT_ERR, "Unable to convert to ASCII") : ip_string); printf(" role = %d\n", nm[i].cln_if[j].cli_role); printf(" node = %d\n", nm[i].cln_if[j].cli_nodeid); printf(" active node = %d\n", nm[i].cln_if[j].cli_active_nodeid); } } } /* * Name: clstat_sleep * * Description: This routine replaces the use of sleep() * * Arguments: time to sleep in seconds * * Return: Exits on error * */ static void clstat_sleep(const int time) { struct timeval tout; tout.tv_sec = time; tout.tv_usec = 0; if (select (0, NULL, NULL, NULL, &tout) == -1) { if (EINTR != errno) { exit (-1); /* exits */ } } return; } /* * Name: register_with_clinfo * * Description: This routine registers or unregisters for event * notifications from cinfo. * This is called when the cluster has gone stable. * * Arguments: action - either 0 to unregister or 1 to register * cluster struct - used to send the cluster id to clinfo * * Return: return code from cl_registereventnotify as long as its * 0, otherwise this routine exits * */ static int register_with_clinfo(const int action, const struct cl_cluster *clstr_buf) { struct cli_enr_req_t en_req; /* Event notification request */ int ret_code; memset(&en_req, 0, sizeof(struct cli_enr_req_t)); en_req.event_id = CL_ALL; en_req.cluster_id = clstr_buf->clc_clusterid; en_req.net_id = -1; en_req.signal_id = SIGUSR1; if (action) { /* register */ /* register the signal hander */ (void) sigset(SIGUSR1, sig_handler); #ifdef DEBUG fprintf(stderr, "register_with_clinfo: registering with clinfo\n"); #endif /* contact clinfo to subscribe for events */ if(ret_code = cl_registereventnotify(1, &en_req)!=CLE_OK ) { fprintf(stderr, "clstat: cl_registereventnotify failed with error %d.", ret_code); exit(1); } } else { /* unregister */ #ifdef DEBUG fprintf(stderr, "register_with_clinfo: UN registering with clinfo\n"); #endif if ( (ret_code = cl_unregistereventnotify(1,&en_req))!=CLE_OK) { fprintf(stderr, "clstat: cl_unregistereventnotify failed with error %d.", ret_code); exit(1); } sigignore(SIGUSR1); /* reset handler for now */ clinfo_signal=0; } return(ret_code); } /* * Name: ifs_is_shared * * Description: This routine is used to avoid displaying shread interfaces * twice in the clstat display(s). We cannot simply rely on the * interface role, since service labels on aliasing networks can * have role == service yet have an entry for each node * like a shread label. * * Arguments: the global node map and number of nodes * the particular interface to test for * * Return: 0 - interface is not shared * 1 - interface is on more than one node and is therefore shared * */ int ifs_is_shared(struct cl_node *nodemap, int num_nodes, struct cl_netif *cln_if) { int i,j; int found = 0; for (i=0; icli_name) && nodemap[i].cln_if[j].cli_interfaceid == cln_if->cli_interfaceid) { /* interface is the same. If it has been found already on another * node, our work is done, otherwise just memeber it found and * continue */ if (found) return(1); found = 1; } } } return(0); } /* * Program: clstat.c - HA6000 cluster status monitor * * Name: main * * Description: This is the main function of clstat. It will parse and check * all the options and data input at start-up. If clstat is being * run interactively, it will branch, calling inter_act_stat. In * automatic mode, auto_stat will be called. * * Arguments: int argc - argument count * char **argv - input arguments and options * * Return: int return - 0 success, ERROR (-1) unsuccessful * * Global Data Affected: NONE */ int TTYmain(int argc, char **argv) { extern char *optarg; extern int optind; int c; int ret; int cluster_number = -1; int moreHelpFileToRead = 1; char *cluster_name = (char *)NULL; char * fgetsReturnPtr = (char *) NULL; char * helpFileName = "/usr/es/sbin/cluster/etc/clstat_cldump.help"; char helpBuffer [2048]; char print_filename[40]; char *p; FILE * helpFile = (FILE *) NULL; if (progname = strrchr(argv[0], '/')) progname++; else progname = argv[0]; #ifndef __LINUX__ (void) setlocale(LC_ALL, ""); p = setlocale(LC_ALL, 0); /* check for "en" or "En", error if not found */ if(!(((*p == 'E' || *p == 'e') && *++p == 'n') || *p == 'C')) { printf(MSGSTR(CLSTAT_UNSUPPORTED, "ASCII mode is not supported in languages other than English\n")); exit(-1); } if(TERM = getenv("TERM")) { tgetent(tx, TERM); CR = tgetstr("cr", &stx_ptr); UP = tgetstr("up", &stx_ptr); CE = tgetstr("ce", &stx_ptr); CL = tgetstr("cl", &stx_ptr); } #endif (void) sigset(SIGCONT, sig_handler); (void) sigset(SIGUSR1, sig_handler); wait_time = 1; rflag = 0; while ((c = getopt(argc, argv, "oaishc:n:r:")) != EOF) { switch (c) { case 'a': break; case 'o': ONCE = 1; break; case 'i': INTERACT = 1; break; case 's': ALLSERVICES = 1; break; case 'c': if((strncmp(optarg, "0", strlen(optarg))) == 0) { cluster_number = 0; } else { if((cluster_number = atoi(optarg)) == 0) { printf(MSGSTR(CLSTAT_NEED_ID, "\n\nThe cluster ID (#) must be provided\n\n")); usage(); exit(-1); } } CLUSTERED = 1; break; case 'n': cluster_name = optarg; CLUSTERNAMED = 1; break; case 'r': rflag = 1; if((wait_time = atoi(optarg)) == 0) { printf(MSGSTR(CLSTAT_NEED_WAIT, "\n\nThe wait time (#) must be provided\n\n")); usage(); exit(-1); } if(wait_time > 30) { printf(MSGSTR(CLSTAT_REFRESH_RESET, "\n\nThe refresh time has been reset to 1 second\n\n")); sleep(3); wait_time = 1; } break; case 'h': helpOptionSpecified=1; break; case '?': printf(MSGSTR(CLSTAT_INVALID_OPT, "Invalid option selected\n\n")); usage(); exit(-1); } } if(optind != argc) { printf(MSGSTR(CLSTAT_EXTRA_ARGS, "\n\nThere are extra arguments provided\n\n")); usage(); exit(-1); } /* * - if the help option is specified (-h) * - generate the checklist to establish * proper functionality and exit with 0. */ if (helpOptionSpecified == 1) { /* * - Open the help file */ helpFile = fopen (helpFileName, "r"); if (helpFile != NULL) { /* * - Read in each line of the help file, * and display to standard out * - exit with zero return code */ while (moreHelpFileToRead) { fgetsReturnPtr = fgets (helpBuffer, sizeof (helpBuffer), helpFile); if (fgetsReturnPtr != NULL) { /* * Print the line to standard out */ fprintf (stdout, helpBuffer); } else { /* * Indicate the processing * of the help file is complete */ moreHelpFileToRead = 0; } } /* * - Close the help file * - Exit with return code 0 */ (void) fclose (helpFile); exit (0); } else { /* * - The help file could not be opened * so generate an error message * - Exit with return code 1 error */ printf (MSGSTR (CLSTAT_NO_HELP_FILE, "\n\nThe %s help file could not be opened.\n\n"), helpFileName); exit (1); } } #ifdef __LINUX__ /* linux does not support curses - ignore all other options than -o */ ONCE=1; #else if(INTERACT && CLUSTERED) { printf(MSGSTR(CLSTAT_ID_MODE, "\n\nCluster ID is only used in non_interactive mode\n\n")); usage(); exit(-1); } if(INTERACT && CLUSTERNAMED) { printf(MSGSTR(CLSTAT_NAME_MODE, "\n\nCluster Name is only used in non_interactive mode\n\n")); usage(); exit(-1); } if(CLUSTERED && CLUSTERNAMED) { printf(MSGSTR(CLSTAT_NAME_ID, "\n\nCluster Name can not be used with Cluster ID\n\n")); usage(); exit(-1); } #endif if((ret=cl_initialize()) != CLE_OK) { /* No need to issue error message here because cl_initialize does */ exit(-1); } #ifndef __LINUX__ if(INTERACT) inter_act_stat(); else #endif auto_stat(cluster_number, cluster_name); } /* * Name: HTMLmain * * Description: This is the main function for the web-based interface to * clstat. It will print out HTML formatted cluster status * information for each cluster found via clinfo. This function * is used when clstat is called via it's CGI/HTML interface, * "clstat.cgi". A webserver can be setup to access clstat.cgi * and display the HTML information to a web browser via a CGI * access request. * * Arguments: None. * * Return: 0 success, -1 error * * Global Data Affected: HTMLmode */ int HTMLmain(void) { int ret; struct cl_cluster *cluster_map; struct cl_node *node_map; struct cl_group *group_map; int num_clusters, num_nodes, num_groups; char *nav_header, tmp[MAXNAMELEN + 50]; int i, j, k; char time_buf[TIME_BUF_SIZE] = {0}; time_t the_time; int tnode, tif; char str_ip[MAXIPLEN]; const char* str_ip_ptr = NULL; HTMLmode = 1; /* Print out HTTP headers for caching control. If supported by the * web browser, these options should cause the browser not to store * the output of this page in it's local cache. We want to make sure * that the client browser always loads the latest version of the * web page. */ printf("Expires: 0\r\n" "Pragma: no-cache\r\n" "Cache-Control: no-cache\r\n"); /* Print the MIME type header. The double newline is used to tell the * web server and web browser where the HTTP headers end and the page * content begins. */ printf("Content-type: text/html\r\n\r\n"); /* Print the top of the HTML page, including the JavaScript required to * auto-refresh the page. * * Explantation of the JavaScript: * Set a timer to execute location.reload() after a certain period. * This will auto-reload the page from the webserver. * There's a bug in Microsoft Internet Explorer that does not * correctly reload the page if there is an anchor reference * in the URL. So we have force the page to scroll to the correct * point by setting the location.hash value to the current location.hash * value, which is the anchor reference. However if we did this * for Netscape Navigator as well, then a bug shows up in Netscape * that causes the page to be constantly refreshed every split second. * This bug also appears in IE 5.5, so we only execute this for IE * less than or greater than 5.5. * The refresh interval shall be 30 seconds unless the user has overriden * this by setting CLSTAT_CGI_REFRESH. */ if ((nav_header=getenv("CLSTAT_CGI_REFRESH")) != (char *)NULL) i = atoi(nav_header); else i = 30; i = i * 1000; /* browser deals in mirco */ printf("\n" "\n" "clstat - HACMP Cluster Status Monitor\n" "\n" "\n" "\n" "\n" "\n" "\n" "
\n", i ); if ((ret = cl_initialize()) != CLE_OK) { printf(MSGSTR(CLSTAT_HTML_INIT_FAILED, "Could not initialize clinfo connection.\n")); printf("\n" "\n"); exit(-1); } if (cl_alloc_clustermap(&cluster_map) == -1) { printf(MSGSTR(CLSTAT_HTML_CLUSTER_MAP_ALLOC_ERROR, "Could not allocate memory for cluster map.\n")); printf("\n" "\n"); exit(-1); } num_clusters = cl_getclusters(cluster_map); if (num_clusters <= 0) { printf(MSGSTR(CLSTAT_HTML_CHECK_CLINFO_1, "Failed retrieving cluster information.

\n\ There are a number of possible causes:
\n\ clinfoES or snmpd subsystems are not active.
\n\ snmp is unresponsive.
\n\ snmp is not configured correctly.
\n\ Cluster services are not active on any nodes.

\n\ Refer to the HACMP Administration Guide for more information.
\n")); printf("\n" "\n"); cl_free_clustermap(cluster_map); exit(-1); } /* Allocate enough space to store the navigational link header for * all the clusters found. The additional 50 characters for each cluster * name leaves enough room for the enclosing HTML anchor tags and the * cluster ID in string form. */ nav_header = (char *)malloc((MAXNAMELEN + 50) * num_clusters); if (nav_header == NULL) { printf(MSGSTR(CLSTAT_HTML_NAV_ALLOC_ERROR, "Could not allocate memory for navigation.\n")); printf("\n" "\n"); cl_free_clustermap(cluster_map); exit(-1); } nav_header[0] = '\0'; for (i = 0; i < num_clusters; i++) { sprintf(tmp, "%s", cluster_map[i].clc_clusterid, cluster_map[i].clc_name); strcat(nav_header, tmp); /* Print some formatted spacing between cluster names. */ if (i != num_clusters - 1) strcat(nav_header, " | "); } /* Start the loop through each cluster. For each cluster, print the cluster * status table, then loop through each node in the cluster, and loop * through all the interfaces on each node. */ for (i = 0; i < num_clusters; i++) { if (cl_alloc_nodemap(&node_map) == -1 || cl_alloc_groupmap(&group_map) == -1) { printf(MSGSTR(CLSTAT_HTML_NODE_MAP_ALLOC_ERROR, "Could not allocate memory for node map.\n")); printf("\n" "\n"); free(nav_header); cl_free_clustermap(cluster_map); exit(-1); } num_nodes = cl_getnodemap(cluster_map[i].clc_clusterid, node_map); the_time = time(0); fmt_date(&the_time, time_buf, TIME_BUF_SIZE); printf("\n", cluster_map[i].clc_clusterid); printf("%s\n", nav_header); printf("

\n"); /* print cluster name, id and time */ printf("\n" "\n" "\n" "\n" "\n", cluster_map[i].clc_name, cluster_map[i].clc_clusterid); printf("\n" "\n" "\n" "\n", time_buf); /* cluster state */ printf("\n" "\n" "\n" "\n", HTML_state_color(cluster_map[i].clc_state), get_state(cluster_map[i].clc_state)); printf("\n" "\n" "\n" "\n"); printf("\n" "\n" "\n" "\n" "
Cluster:%s (%d)
Last Update:%s
State:
%s
SubState:
", HTML_substate_color(cluster_map[i].clc_substate)); /* If the substate is ERROR, have the text blink. Note that blinking * text is only supported in Netscape Navigator. */ if (cluster_map[i].clc_substate == CLSS_ERROR) { printf("%s", get_substate(cluster_map[i].clc_substate)); } else { printf("%s", get_substate(cluster_map[i].clc_substate)); } printf("
Nodes:%d
\n", num_nodes); /* print a header */ printf("

\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n"); /* Loop through each node in the cluster. */ for (j = 0; j < num_nodes; j++) { /* Loop through each interface defined on the current node. */ for (k = 0; k < node_map[j].cln_nif; k++) { if (k == 0) { printf("\n"); /* We conserve webpage space by printing the name and state of the * node on same line as the first interface defined on that node. */ printf("\n" "\n", node_map[j].cln_nodename, HTML_state_color(node_map[j].cln_state), get_state(node_map[j].cln_state)); } /* first print all the boot and standby on this node */ if ((node_map[j].cln_if[k].cli_role != CL_INT_ROLE_BOOT && node_map[j].cln_if[k].cli_role != CL_INT_ROLE_STANDBY)) continue; printf("\n"); if (k) { /* We have to print filler table data fields if this is not the first * interface defined on the node. This takes the place of the * node name and state fields that appear on the first interface * row. */ printf("\n" "\n"); } bzero(str_ip, sizeof(str_ip)); switch(((struct sockaddr*)&node_map[j].cln_if[k].cli_addr6)->sa_family) { case AF_INET: str_ip_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)&node_map[j].cln_if[k].cli_addr6)->sin_addr, str_ip, sizeof(str_ip)); break; case AF_INET6: str_ip_ptr = inet_ntop(AF_INET6, &((struct sockaddr_in6*)&node_map[j].cln_if[k].cli_addr6)->sin6_addr, str_ip, sizeof(str_ip)); break; } /* print the interface info - html style */ printf("\n" "\n" "\n" "\n", node_map[j].cln_if[k].cli_name, node_map[j].cln_if[k].cli_interfaceid, str_ip, HTML_state_color(node_map[j].cln_if[k].cli_state), get_state(node_map[j].cln_if[k].cli_state)); } /* for all interfaces on this node */ /* we have displayed the information for all the "local" interfaces - search for (and display) any service addresses also on this node */ for(tnode=0; tnode < num_nodes; tnode++) { for(tif=0; tif\n"); printf("\n" "\n"); bzero(str_ip, sizeof(str_ip)); switch(((struct sockaddr*)&node_map[tnode].cln_if[tif].cli_addr6)->sa_family) { case AF_INET: str_ip_ptr = inet_ntop(AF_INET, &((struct sockaddr_in*)&node_map[tnode].cln_if[tif].cli_addr6)->sin_addr, str_ip, sizeof(str_ip)); break; case AF_INET6: str_ip_ptr = inet_ntop(AF_INET6, &((struct sockaddr_in6*)&node_map[tnode].cln_if[tif].cli_addr6)->sin6_addr, str_ip, sizeof(str_ip)); break; } /* print the interface info - html style */ printf("\n" "\n" "\n" "\n", node_map[tnode].cln_if[tif].cli_name, node_map[tnode].cln_if[tif].cli_interfaceid, str_ip, HTML_state_color(node_map[tnode].cln_if[tif].cli_state), get_state(node_map[tnode].cln_if[tif].cli_state)); } /* active on this node */ } /* for tif */ } /* for tnodes */ /* all interfaces on this node have been displayed, now search for */ /* any resource groups */ num_groups = cl_getgroupmap(cluster_map[i].clc_clusterid, group_map); if (num_groups > 0) { /* Loop through each group in the cluster. */ for (k = 0; k < num_groups; k++) { if (notOfflineGroupState(&group_map[k], node_map[j].cln_nodeid)) { javaGroupInfo(&group_map[k], node_map, node_map[j].cln_nodeid); } /* not offline */ } /* for all groups */ } /* if there are groups to display */ if (j != num_nodes - 1) { /* add space between nodes */ printf("\n"); } } /* for all nodes in this cluster */ printf("
NodeStateInterfaceAddressState
%s
%s
%s (%d)%s
%s
%s (%d)%s
%s
\n"); if (i != num_clusters - 1) { printf("

\n" "


\n" "

\n"); } } /* for all clusters */ printf("\n" "\n"); cl_free_groupmap(group_map); cl_free_nodemap(node_map); cl_free_clustermap(cluster_map); exit(0); } #ifndef __LINUX__ /* * Name: inter_act_stat * * Description: This function is called if clstat is run interactively. It * will call the clinfo API to find all accessible clusters and * display them in a list on the screen. All action from this * screen is initiated by user input, with get_cluster_info called * for a detailed display of a cluster status. * * Arguments: NONE * * Return: 0 complete * * Global Data Affected: NONE */ int inter_act_stat() { int cluster_cnt; int i; int the_nbr; int loop = 1; char re_spond[80]; struct cl_cluster *cluster_map; char quit = 'q'; if (cl_alloc_clustermap(&cluster_map) == -1) { printf("Could not allocate memory for cluster_map.\n"); exit(-1); } resetClustermap(cluster_map); while (re_spond[0] != quit) { memset(re_spond, '\0', sizeof(re_spond)); redisplay = 0; tputs(CL, 1, term_dumb); printf(MSGSTR(CLSTAT_STAT_MON, "\n\t\t%s - HACMP Cluster Status Monitor\n"), progname); printf("\t\t-------------------------------------\n\n"); cluster_cnt = cl_getclusters(cluster_map); if(cluster_cnt <= 0) printf(MSGSTR(CLSTAT_NO_ACTIVE, "\n\n\t\tTHERE ARE NO CLUSTERS CURRENTLY ACTIVE\n\n\n")); else { printf(MSGSTR(CLSTAT_ACTIVE_NUM, "Number of clusters active: %d\n\n"), cluster_cnt); printf(MSGSTR(CLSTAT_MSG_20, "\t\tID\tName\t\tState\n\n")); for(i=0; i < cluster_cnt; i++) printf("%18d %9s %15s\n", cluster_map[i].clc_clusterid, cluster_map[i].clc_name, get_state(cluster_map[i].clc_state)); } printf(MSGSTR(CLSTAT_SELECT_OPT, "\n\n\nSelect an option:\n")); printf("\t# - the Cluster ID \t\t\t%c- quit\n\n",'q'); loop = 1; while(loop) { gets(re_spond); if(re_spond[0] == 'q') { loop--; exit(0); } if(re_spond[0] == '?') { show_commands(0); loop--; } else if(re_spond[0] != '\0' && ! redisplay) { if(cluster_cnt > 0) { the_nbr = atoi(re_spond); for(i=0; i/dev/null"; char check_sub_mib[512]="grep \"^VACM_VIEW *defaultView *1.3.6.1.4.1.2.3.1.2.1.5 *- *included *-\" /etc/snmpdv3.conf 2>/dev/null"; char output_array[512]; char search_string[15]="VACM_VIEW"; if (cl_alloc_clustermap(&cluster_map) == -1) { printf("Could not allocate memory for cluster_map.\n"); exit(-1); } while(clid == NO_CLID) { number_clstrs = cl_getclusters(cluster_map); if (number_clstrs < 0) { printf(MSGSTR(CLSTAT_CHECK_CLINFO_1, "Failed retrieving cluster information.\n\n\ There are a number of possible causes:\n\ clinfoES or snmpd subsystems are not active.\n\ snmp is unresponsive.\n\ snmp is not configured correctly.\n\ Cluster services are not active on any nodes.\n\n\ Refer to the HACMP Administration Guide for more information.\n")); #ifdef SNMP_CONF_CHECK output_array[0]=0; fp = popen(check_main_mib,"r"); if(fp == NULL) { clid = ERROR; return(ERROR); } else { returnval = fgets(output_array,512,fp); if (returnval != NULL) { /* Entry found so return */ pclose(fp); clid = ERROR; return(ERROR); } pclose(fp); fp = popen(check_sub_mib,"r"); if(fp == NULL) { clid = ERROR; return(ERROR); } else { returnval = NULL; output_array[0]=0; returnval = fgets(output_array,512,fp); if (returnval != NULL) { pclose(fp); clid = ERROR; return(ERROR); } printf(MSGSTR(CLSTAT_README_MSG, "\nInternet MIB tree not enabled. Please refer the PowerHA \nreadme file for more information on how to enable it.\n")); pclose(fp); } } #endif clid = ERROR; return(ERROR); } switch(number_clstrs) { case 0: if(first) { first--; #ifndef __LINUX__ tputs(CL, 1, term_dumb); #endif printf(MSGSTR(CLSTAT_STAT_MON, "\t\t%s - HACMP Cluster Status Monitor\n"), progname); printf("\t\t-------------------------------------\n"); printf(MSGSTR(CLSTAT_NO_ACTIVE, "\n\n\n\t\t\tTHERE ARE NO ACTIVE CLUSTERS\n\n\n")); printf(MSGSTR(CLSTAT_SEARCH, "\n\t\tTHE PROGRAM WILL CONTINUE SEARCHING FOR ONE\n\n")); } break; case 1: clid = cluster_map[0].clc_clusterid; break; default: printf(MSGSTR(CLSTAT_MORE_ACCESS, "\n\nThere is more than one cluster accessible.\n")); printf(MSGSTR(CLSTAT_PROVIDE1, "Either provide the cluster to look for, or run\nthe program interactively (or try again).\n\n")); usage(); clid = ERROR; return(ERROR); break; } } cl_free_clustermap(cluster_map); return(clid); } /* * Name: get_cluster_info * * Description: This function performs the loop that calls the clinfo APIs * to obtain cluster information and display on the screen. If * clstat is in automatic mode, the function will wait the specified * time in each loop. In interactive mode the function will call * get_clstr_rspns (function) to determine the user input and process * that. * * Changed by SAM, 7-25-94, for Fallwell. clstat now functions * the same in interactive mode and auto mode except that when * you quit, you get the interactive response instead of exiting * clstat. * * Arguments: int clstr_ID - ID of cluster being monitored * * Return: 0 - complete * * Global Data Affected: NONE */ int get_cluster_info(int clstr_ID) { int result, i, j, update, refresh, numStars, status; struct cl_cluster clstr_buf, HOLD_cluster; struct cl_node *nodemap; struct cl_node *HOLD_NODES; struct cl_group *groupmap; struct cl_group *HOLD_GROUPS; int hold_ID; time_t start_time, done_time; char BodyTxt[65536]; /* Enough to hold 2 clusters w 8nodes/8 intfcs. */ char StatusTxt[256]; char HeaderTxt[1024]; #ifndef __LINUX__ WINDOW *winBody, *winStatusLine, *winHeader; #endif char command[1], tmp[256], *pc; int lineCount = 0; int segCount = 0; int sizeWinBody = 0; char time_buf[TIME_BUF_SIZE] = {0}, state_buf[STATE_BUF_SIZE] = {0}; char temp[256]; int tnode, tif; char str_ip[MAXIPLEN+1]; /* this flag tells the main loop to sample clinfo for updates */ int check_for_updates = 5; #define WIN_HEADER_SIZE 10 /* Size of cluster status window */ if (cl_alloc_nodemap(&nodemap) == -1) { printf("Could not allocate memory for nodemap.\n"); exit(-1); } resetNodemap(nodemap); /* #define DUMP_AND_EXIT */ #ifdef DUMP_AND_EXIT nbr_nodes = cl_getnodemap(clstr_ID, nodemap); cl_dump_nodemap(nodemap, nbr_nodes); exit(0); #endif if (cl_alloc_nodemap(&HOLD_NODES) == -1) { printf("Could not allocate memory for HOLD_NODES.\n"); exit(-1); } resetNodemap(HOLD_NODES); if (cl_alloc_groupmap(&groupmap) == -1) { printf("Could not allocate memory for groupmap.\n"); exit(-1); } resetGroupmap(groupmap); if (cl_alloc_groupmap(&HOLD_GROUPS) == -1) { printf("Could not allocate memory for HOLD_GROUPS.\n"); exit(-1); } resetGroupmap(HOLD_GROUPS); bzero(&HOLD_cluster, sizeof(struct cl_cluster)); done_time = time(0); /* This is virtually the main loop of clstat. */ if (!ONCE) { #ifndef __LINUX__ initscr(); /* Initialize curses */ if (cur_term->Lines < 24 || cur_term->Columns < 80) { /* This keeps the tty from wrapping and looking unreadable */ printf(MSGSTR(CLSTAT_DISPLAY_SIZE, "Display must be at least 24 lines by 80 columns\n")); endwin(); exit (0); } /* Set up the curses windows. winBody holds all cluster info except * command status line. Leave 2 lines at bottom of display for this line. * winStatusLine holds the b-back, f-forward, q-quit status line. * winHeader holds the cluster status info. */ winHeader = newwin (WIN_HEADER_SIZE, 0, 0, 0); sizeWinBody = cur_term->Lines - 2 - WIN_HEADER_SIZE; winBody = newwin (sizeWinBody, 0, WIN_HEADER_SIZE, 0); winStatusLine = newwin (1, 0, cur_term->Lines - 1, 0); if ( winBody == NULL || winHeader == NULL || winStatusLine == NULL ) { printf(MSGSTR(CLSTAT_MEM_PROB, "Memory problems. Couldn't create curses window.\n")); endwin(); exit (0); } /* Figure out how to nicely draw the status bar */ numStars = (cur_term->Columns - 32) / 2; #else numStars = 32; #endif memset (StatusTxt, '\0', sizeof(StatusTxt) ); for (i = 0; i < numStars; i++) { strcat(StatusTxt, "*"); } sprintf(temp, " %c/forward, %c/back, %c/refresh, %c/quit \0",'f','b','r','q'); strcat(StatusTxt, temp); for (i = 0; i < numStars; i++) { strcat(StatusTxt, "*"); } #ifndef __LINUX__ mvwaddstr(winStatusLine, 0, 0, StatusTxt); nodelay(winStatusLine, TRUE); noecho(); cbreak(); #endif } command[0] = '\0'; while (0 != strcmp(command, "q")) { struct cli_en_msg_t en_msg; int last_update; start_time = time(0); /* check for events available from clinfo */ if (clinfo_signal) { #ifdef DEBUG fprintf(stderr, "main loop: signal count %d\n", clinfo_signal); #endif /* read events even though we dont actually do anything with it */ while (clinfo_signal--) { int rc = cl_getevent(&en_msg); #ifdef DEBUG fprintf(stderr, "main loop: cl_getevent returned %d\n", rc); #endif } /* unregister for event notifications */ register_with_clinfo(0, &clstr_buf); /* make sure we sample a few more time before going back to */ /* signal mode */ check_for_updates = 5; } #ifdef DEBUG fprintf(stderr, "main loop: check_for_updates is %d\n",check_for_updates); #endif if (check_for_updates) { if ((result = cl_getcluster(clstr_ID, &clstr_buf)) != CLE_OK) { if(INTERACT) { #ifndef __LINUX__ endwin(); #endif return(10); } clstr_buf.clc_clusterid = clstr_ID; strcpy(clstr_buf.clc_name, HOLD_cluster.clc_name); clstr_buf.clc_state = CLS_DOWN; resetNodemap(nodemap); nbr_nodes = 0; resetGroupmap(groupmap); nbr_groups = 0; } else { nbr_nodes = cl_getnodemap(clstr_ID, nodemap); if(nbr_nodes < 1 || nbr_nodes > CL_MAXNODES) { if(INTERACT) { #ifndef __LINUX__ endwin(); #endif return(10); } nbr_nodes = 0; memset(clstr_buf.clc_primary, '\0', CL_MAXNAMELEN); clstr_buf.clc_state = CLS_DOWN; resetNodemap(nodemap); } nbr_groups = cl_getgroupmap(clstr_ID, groupmap); if(nbr_groups < 1 || nbr_groups > CL_MAXGROUPS) { nbr_groups = 0; resetGroupmap(groupmap); } } update=0; refresh=0; if (bcmp(&HOLD_cluster, &clstr_buf, sizeof(struct cl_cluster))) { bcopy(&clstr_buf, &HOLD_cluster, sizeof(struct cl_cluster)); update = 1; } else if (0 != compareGroupmap(HOLD_GROUPS, groupmap)) { HOLD_GROUPS = groupmap; update = 1; } else if (0 != compareNodemap(HOLD_NODES, nodemap)) { copyNodemap(nodemap, HOLD_NODES); update = 1; } else { for (i = 0; i 15) { /* every so often we want to resample cluster state just */ /* to make sure clinfo is accessable */ #ifdef DEBUG fprintf(stderr, "main loop: last_update fired\n"); #endif last_update = 0; if ((result = cl_getcluster(clstr_ID, &clstr_buf)) == CLE_OK) { if (clstr_buf.clc_substate != CLSS_STABLE) check_for_updates = 5; } else check_for_updates = 5; /* setting check_for_updates will cause the entire config */ /* to be checked next time around */ } } if(redisplay) { update=1; redisplay=0; } if ( 0 == strcmp(command, "f") || 0 == strcmp(command, "b") || 0 == strcmp(command, "r") ) { update = 1; } if(rflag) { update = 1; } if(ONCE || update) { #ifndef __LINUX__ if (!ONCE) { werase(winHeader); werase(winBody); } #endif memset(HeaderTxt, '\0', sizeof(HeaderTxt) ); memset(BodyTxt, '\0', sizeof(BodyTxt) ); lineCount = 0; sprintf(HeaderTxt, "\n"); sprintf(tmp, MSGSTR(CLSTAT_STAT_MON, "\t\t%s - HACMP Cluster Status Monitor\n"), progname); strncat(HeaderTxt, tmp, sizeof(tmp) ); sprintf(tmp,"\t\t-------------------------------------\n"); strncat(HeaderTxt, tmp, sizeof(tmp) ); (void) fmt_date(&start_time, time_buf, TIME_BUF_SIZE); sprintf(tmp, "\nCluster: %s\t(%d)\n%s\n", clstr_buf.clc_name, clstr_buf.clc_clusterid, time_buf); strncat(HeaderTxt, tmp, sizeof(tmp) ); sprintf(tmp, MSGSTR(CLSTAT_MSG_42, "\t\tState: %s\t\tNodes: %d\n"), get_state(clstr_buf.clc_state), nbr_nodes); strncat(HeaderTxt, tmp, sizeof(tmp) ); sprintf(tmp, MSGSTR(CLSTAT_MSG_43, "\t\tSubState: %s\n\n"), get_substate(clstr_buf.clc_substate)); strncat(HeaderTxt, tmp, sizeof(tmp) ); if(clstr_buf.clc_state == CLS_DOWN || clstr_buf.clc_state == CLS_UP) { for(i=0; i < nbr_nodes; i++) { sprintf(tmp, MSGSTR(CLSTAT_MSG_44, "\tNode: %s\t\tState: %s\n"), nodemap[i].cln_nodename, get_state(nodemap[i].cln_state)); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; for(j=0; jsa_family) { case AF_INET: inet_ntop(AF_INET, &((struct sockaddr_in*)&nodemap[i].cln_if[j].cli_addr6)->sin_addr, str_ip, sizeof(str_ip)); break; case AF_INET6: inet_ntop(AF_INET6, &((struct sockaddr_in6*)&nodemap[i].cln_if[j].cli_addr6)->sin6_addr, str_ip, sizeof(str_ip)); break; } sprintf(tmp, MSGSTR(CLSTAT_MSG_46, "\tAddress: %s\n"), str_ip); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; sprintf(tmp, MSGSTR(CLSTAT_MSG_47, "\t\t\t\t\t\tState: %s\n"), get_state(nodemap[i].cln_if[j].cli_state)); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; } /* * We have displayed the all the boot interfaces, now look * for any service labels which may be up on this node. * Note that we look at all services on all nodes since * there could be a takeover label currently on this node. */ for(tnode=0; tnode < nbr_nodes; tnode++) { for(tif=0; tifsa_family) { case AF_INET: inet_ntop(AF_INET, &((struct sockaddr_in*)&nodemap[tnode].cln_if[tif].cli_addr6)->sin_addr, str_ip, sizeof(str_ip)); break; case AF_INET6: inet_ntop(AF_INET6, &((struct sockaddr_in6*)&nodemap[tnode].cln_if[tif].cli_addr6)->sin6_addr, str_ip, sizeof(str_ip)); break; } sprintf(tmp, MSGSTR(CLSTAT_MSG_46, "\tAddress: %s\n"), str_ip); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; sprintf(tmp, MSGSTR(CLSTAT_MSG_47, "\t\t\t\t\t\tState: %s\n"), get_state(nodemap[tnode].cln_if[tif].cli_state)); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; } } } /* for all nodes */ /* * We have displayed the all the interfaces, now show * the performance data */ #ifdef SUPPORTS_PERF_DATA sprintf(tmp, /* MSGSTR(CLSTAT_MSG_45, */ "\t CPU (idle) (%d)", nodemap[i].cln_glidle); strncat(BodyTxt, tmp, sizeof(tmp) ); sprintf(tmp, /* MSGSTR(CLSTAT_MSG_45, */ "\t\t\tMemory (free) (%d)\n", nodemap[i].cln_real_mem_free); strncat(BodyTxt, tmp, sizeof(tmp) ); lineCount++; #endif /* * We have displayed the node and all its interfaces. * Now look through the list of resource groups for this * node - if the state is anything other than offline, * display the group and state. */ for(j=0; j sizeWinBody) { if (0 == strcmp(command, "b") ) { refresh = 1; if (segCount > 0) { segCount--; } } else if (0 == strcmp(command, "f") ) { refresh = 1; if (lineCount > segCount * sizeWinBody) { segCount++; } } else if (0 == strcmp(command, "r") ) { refresh = 1; } } if (segCount > 0) { pc = BodyTxt; i = 0; while (pc != NULL) { pc = strchr(pc, '\n'); i++; pc++; if (i >= segCount * sizeWinBody) { break; } } if (refresh) { wclear(winBody); touchwin(winBody); } if ((char *)NULL != pc) { mvwaddstr(winBody, 0, 0, pc); } } else { if (refresh) { wclear(winBody); touchwin(winBody); } mvwaddstr(winBody, 0, 0, BodyTxt); } wclear(winHeader); touchwin(winHeader); mvwaddstr(winHeader, 0, 0, HeaderTxt); wrefresh(winHeader); wrefresh(winBody); if (winStatusLine != NULL) { wrefresh(winStatusLine); command[0] = '\0'; } if(rflag) { clstat_sleep(wait_time); } } else { clstat_sleep(wait_time); } if (winStatusLine != NULL) { sprintf(command, "%c", wgetch(winStatusLine) ); } } cl_free_nodemap (nodemap); cl_free_nodemap (HOLD_NODES); cl_free_groupmap (groupmap); cl_free_groupmap (HOLD_GROUPS); if (winStatusLine != NULL) { wclear(winStatusLine); touchwin(winStatusLine); wrefresh(winStatusLine); } endwin(); #else } } #endif } #ifndef __LINUX__ /* * Name: get_clstr_rspns * * Description: This function is called in interactive mode (only) when a user * has entered input that must be acted upon. The function will * determine whether the input is valid for the existing environment. * The function returns 0 if the input is "r" to return to the cluster * list display, returns the end of looping time for non-interactive * mode ("l time"input), current time otherwise (for immediate update). * * Arguments: NONE * * Return: time_t done_time - the time that non-interactive display will end * * Global Data Affected: NONE */ time_t get_clstr_rspns() { static time_t done_time; int sleepy_time; int loop = 1; char node_respond[80]; while(loop) { echo(); nocbreak(); printf("> "); gets(node_respond); tputs(CE, 1, term_dumb); if(redisplay) node_respond[0] = '\0'; switch(node_respond[0]) { case 'r': echo(); nocbreak(); return(0); break; case 'l': /* Loop (sleep) for a time */ if((sleepy_time = atoi(node_respond+1)) == 0) { printf(MSGSTR(CLSTAT_INVALID_TIME, "\tInvalid time provided for automatic mode\n")); break; } done_time = time(0); done_time += sleepy_time; printf(MSGSTR(CLSTAT_AUTO, "\t%s is now in automatic mode for %d seconds\n"), progname, sleepy_time); tputs(UP, 1, term_dumb); tputs(UP, 1, term_dumb); tputs(CE, 1, term_dumb); tputs(UP, 1, term_dumb); printf("\n"); loop--; break; case '\0': done_time = time(0); loop--; break; case '?': show_commands(1); done_time = time(0); loop--; break; default: printf("\tInvalid clstat command - enter %c to see commands\n",'?'); break; } tputs(UP, 1, term_dumb); tputs(UP, 1, term_dumb); tputs(CE, 1, term_dumb); } echo(); nocbreak(); return(done_time); } #endif /* * Name: resourceStateStr * * Description: Converts the numeric resource state value to a character string * for use in screen displays. * * Arguments: resource group handle and node id * * Return: char * state_name - the equivalent character string of the state * * Global Data Affected: NONE */ char * resourceStateStr(struct cl_group *pGroup, int node_id) { char *state; int i; for (i = 0; i < pGroup->clg_num_nodes; i++) { if (pGroup->clg_node_ids[i] == node_id) { switch (pGroup->clg_node_states[i]) { case CL_RGNS_ONLINE: return("On line"); break; case CL_RGNS_OFFLINE: return("Off line"); break; case CL_RGNS_ACQUIRING: return("Acquiring"); break; case CL_RGNS_RELEASING: return("Releasing"); break; case CL_RGNS_ERROR: return("Error"); break; case CL_RGNS_ONLINE_SECONDARY_STATE: return("Online (Secondary)"); break; case CL_RGNS_ONLINE_PEER_STATE: return("Online (Peer)"); break; case CL_RGNS_ACQUIRING_SECONDARY_STATE: return("Acquiring (Secondary)"); break; case CL_RGNS_ACQUIRING_PEER_STATE: return("Acquiring (Peer)"); break; case CL_RGNS_RELEASING_SECONDARY_STATE: return("Releasing (Secondary)"); break; case CL_RGNS_RELEASING_PEER_STATE: return("Releasing (Peer)"); break; case CL_RGNS_ERROR_SECONDARY_STATE: return("Error (Secondary)"); break; case CL_RGNS_TEMP_ERROR_STATE: return("Temp Error"); break; case CL_RGNS_TEMP_ERROR_SECONDARY_STATE: return("Temp Error (Secondary)"); break; case CL_RGNS_UNMANAGED_STATE: return("Unmanaged"); break; case CL_RGNS_UNMANAGED_SECONDARY_STATE: return("Unmanaged(Secondary)"); break; case CL_RGNS_OFFLINE_DUE_TO_FALLOVER: return("Offline due to failover"); break; case CL_RGNS_OFFLINE_DUE_TO_PARENT_OFFLINE: return("Offline due to parent offline"); break; case CL_RGNS_OFFLINE_DUE_TO_LACK_OF_NODE: return("Offline due to lack of node"); break; case CL_RGNS_OFFLINE_DUE_TO_TARGET_OFFLINE: return("Offline due to target offline"); break; case CL_RGNS_INVALID: default: return( MSGSTR(CLSTAT_STATE_UNDEFINED, "UNDEFINED")); break; } } } return(NULL); } /* * Name: resourceStateColor * * Description: Converts the numeric resource state value to a "color" string * for use in HTML output * * Arguments: resource group handle and node id * * Return: char * color - the equivalent color representing the state * * Global Data Affected: NONE */ char * resourceStateColor(struct cl_group *pGroup, int node_id) { char *color; int i; for (i = 0; i < pGroup->clg_num_nodes; i++) { if (pGroup->clg_node_ids[i] == node_id) { switch (pGroup->clg_node_states[i]) { case CL_RGNS_ONLINE: /* Green */ return("\"#00FF00\""); break; case CL_RGNS_OFFLINE: case CL_RGNS_ERROR: case CL_RGNS_ERROR_SECONDARY_STATE: case CL_RGNS_INVALID: case CL_RGNS_TEMP_ERROR_STATE: case CL_RGNS_TEMP_ERROR_SECONDARY_STATE: case CL_RGNS_OFFLINE_DUE_TO_FALLOVER: case CL_RGNS_OFFLINE_DUE_TO_PARENT_OFFLINE: case CL_RGNS_OFFLINE_DUE_TO_LACK_OF_NODE: case CL_RGNS_OFFLINE_DUE_TO_TARGET_OFFLINE: case CL_RGNS_OFFLINE_DUE_TO_SOURCE_OFFLINE: /* Red */ return("\"#FF0000\""); break; case CL_RGNS_ACQUIRING: case CL_RGNS_ACQUIRING_SECONDARY_STATE: case CL_RGNS_ACQUIRING_PEER_STATE: /* Aqua */ return("\"#00FFFF\""); break; case CL_RGNS_RELEASING: case CL_RGNS_RELEASING_SECONDARY_STATE: case CL_RGNS_RELEASING_PEER_STATE: /* Yellow */ return("\"#FFFF00\""); break; case CL_RGNS_ONLINE_SECONDARY_STATE: case CL_RGNS_ONLINE_PEER_STATE: /* Blue */ return("\"#0000FF\""); break; default: return( MSGSTR(CLSTAT_STATE_UNDEFINED, "UNDEFINED")); break; } } } return(NULL); } /* * Name: get_state * * Description: Converts the numeric state value to a character string for use * in screen displays. * * Arguments: int stat_nbr - value for state (of node, cluster, interface) * * Return: char * state_name - the equivalent character string of the state * * Global Data Affected: NONE */ char *get_state(int stat_nbr) { char *state; switch(stat_nbr) { case CLS_INVALID: state = MSGSTR(CLSTAT_STATE_INVALID, "INVALID"); break; case CLS_VALID: state = MSGSTR(CLSTAT_STATE_VALID, "VALID"); break; case CLS_UP: state = MSGSTR(CLSTAT_STATE_UP, "UP"); break; case CLS_DOWN: state = MSGSTR(CLSTAT_STATE_DOWN, "DOWN"); break; case CLS_UNKNOWN: state = MSGSTR(CLSTAT_STATE_UNKNOWN, "UNKNOWN"); break; case CLS_GRACE: state = MSGSTR(CLSTAT_STATE_GRACE, "GRACE"); break; case CLS_JOINING: state = MSGSTR(CLSTAT_STATE_JOINING, "JOINING"); break; case CLS_LEAVING: state = MSGSTR(CLSTAT_STATE_LEAVING, "LEAVING"); break; case CLS_IN_USE: state = MSGSTR(CLSTAT_STATE_IN_USE, "IN_USE"); break; case CLS_PRIMARY: state = MSGSTR(CLSTAT_STATE_PRIMARY, "PRIMARY"); break; default: state = MSGSTR(CLSTAT_STATE_UNDEFINED, "UNDEFINED"); break; } return(state); } /* * Name: get_substate * * Description: Converts the numeric substate value to a character string for use * in screen displays. * * Arguments: int stat_nbr - value for substate (of cluster) * * Return: char * state_name - the equivalent character string of the state * * Global Data Affected: NONE */ char *get_substate(int stat_nbr) { char *state; switch(stat_nbr) { case CLSS_STABLE: state = MSGSTR(CLSTAT_SUBSTATE_STABLE, "STABLE"); break; case CLSS_UNSTABLE: state = MSGSTR(CLSTAT_SUBSTATE_UNSTABLE, "UNSTABLE"); break; case CLSS_ERROR: state = MSGSTR(CLSTAT_SUBSTATE_ERROR, "ERROR"); break; case CLSS_RECONFIG: state = "RECONFIG"; break; case CLSS_UNKNOWN: state = MSGSTR(CLSTAT_SUBSTATE_UNKNOWN, "UNKNOWN"); break; default: state = MSGSTR(CLSTAT_SUBSTATE_UNDEFINED, "UNDEFINED"); break; } return(state); } /* * Name: HTML_state_color * * Description: Returns a hex color code based on the numeric state * value. For use in HTML formatted output. * * Arguments: int state : numeric state value * * Return: A string containing the hex color value. * * Global Data Affected: NONE * */ char *HTML_state_color(int state) { switch(state) { case CLS_UP: case CLS_VALID: /* Green */ return("\"#00FF00\""); case CLS_DOWN: case CLS_INVALID: /* Red */ return("\"#FF0000\""); case CLS_GRACE: case CLS_LEAVING: /* Yellow */ return("\"#FFFF00\""); case CLS_JOINING: /* Aqua */ return("\"#00FFFF\""); case CLS_IN_USE: case CLS_PRIMARY: /* Magenta */ return("\"#FF00FF\""); case CLS_UNKNOWN: default: /* UNDEFINED */ /* Blue */ return("\"#0000FF\""); } } /* * Name: HTML_substate_color * * Description: Returns a hex color code based on the numeric substate * value. For use in HTML formatted output. * * Arguments: int state : numeric substate value * * Return: A string containing the hex color value. * * Global Data Affected: NONE * */ char *HTML_substate_color(int substate) { switch(substate) { case CLSS_STABLE: /* Green */ return("\"#00FF00\""); case CLSS_ERROR: /* Red */ return("\"#FF0000\""); case CLSS_UNSTABLE: case CLSS_RECONFIG: /* Yellow */ return("\"#FFFF00\""); case CLSS_UNKNOWN: default: /* UNDEFINED */ /* Blue */ return("\"#0000FF\""); } } /* * Name: fmt_date * * Description: Generates a string with the current date for use in the screen * displays. Format depends on current locale. * * Arguments: time_t * time_nbr - pointer to structure with the current time * * Return: char * buf - buffer in which to store formatted time string * rc - return code from strftime * * Global Data Affected: NONE */ size_t fmt_date(time_t *time_nbr, char *buf, size_t max_size) { size_t rc; rc = strftime(buf, max_size, nl_langinfo(D_T_FMT), localtime(time_nbr)); return(rc); } /* * Name: make_filename * * Description: Creates a filename for output file to be used to print screens. * This function is called only if the print options is flagged at * start-up without a file also provided. The file is named * according to format: "/tmp/clstr_.", where the date is * mmddyy format and pid is the process ID. * * Arguments: NONE * * Return: char * the_filename - pointer to filename of created output file * * Global Data Affected: NONE */ char *make_filename() { int progid; char the_date[5]; static char the_filename[60]; struct tm *time_ptr; time_t current_time; progid = getpid(); current_time = time(0); time_ptr = localtime(¤t_time); sprintf(the_date, "%d%d%d", time_ptr->tm_mon + 1, time_ptr->tm_mday, time_ptr->tm_year); sprintf(the_filename, "/tmp/clstat_%s.%d", the_date, progid); return(the_filename); } /* * Name: usage * * Description: Prints the program usage message. * * Arguments: NONE * * Return: NONE * * Global Data Affected: NONE */ void usage() { printf(MSGSTR(CLSTAT_USAGE2,"usage: %s [-c cluster ID | -n cluster_name] [-i] [-r seconds] [-a|-o] [-s] [-h]\n\n"), progname); printf(MSGSTR(CLSTAT_c_OPT," -c cluster ID > run in automatic (non-interactive) mode for the\n specified cluster. \n")); printf(MSGSTR(CLSTAT_n_OPT," -n name > run in automatic (non-interactive) mode for the\n specified cluster name. \n")); printf(MSGSTR(CLSTAT_i_OPT," -i > run in interactive mode\n")); printf(MSGSTR(CLSTAT_r_OPT," -r seconds > number of seconds between each check of the\n cluster status\n")); printf(MSGSTR(CLSTAT_a_OPT," -a > run ascii version.\n")); printf(MSGSTR(CLSTAT_o_OPT," -o > run once and exit.\n")); printf(MSGSTR(CLSTAT_s_OPT," -s > display both up and down service labels.\n")); printf(MSGSTR(CLSTAT_h_OPT," -h > display help for clstat configuration issues.\n")); } /* * Name: term_dumb * * Description: Dummy function that is called by tputs for putchar * * Arguments: NONE * * Return: NONE * * Global Data Affected: NONE */ void term_dumb(char c) { putchar(c); } /* * Name: show_commands * * Description: Displays the command options from the screens * * Arguments: NONE * * Return: NONE * * Global Data Affected: NONE */ void show_commands(int detail) { char any_act[60]; #ifndef __LINUX__ tputs(CL, 1, term_dumb); #endif printf(MSGSTR(CLSTAT_STAT_MON,"\t\t%s - HACMP Cluster Status Monitor\n"), progname); printf("\t\t-------------------------------------\n\n"); if(detail) { printf(MSGSTR(CLSTAT_ALLOWED_DETAIL_CMDS,"Commands allowed from the detailed cluster info screen:\n\n")); printf(MSGSTR(CLSTAT_CMD_LIST,"\tr : return to cluster list screen\n")); printf(MSGSTR(CLSTAT_CMD_AUTO,"\tl <#> : program will go into automatic mode for # seconds\n\t If the cluster info changes, the display will be \n\t updated. Note # must be a numeric value\n")); printf(MSGSTR(CLSTAT_CMD_DISP,"\t[ENTER] : the information will be updated immediately\n")); } else { printf(MSGSTR(CLSTAT_ALLOWED_LIST_CMDS,"Commands allowed from the cluster list screen:\n\n")); printf("\t%c : exit the program\n",'q'); printf(MSGSTR(CLSTAT_CMD_DETAIL,"\t# : display the detailed cluster info of the cluster \n\t with the ID number of #.\n")); printf(MSGSTR(CLSTAT_DISP_LIST,"\t[ENTER] : the cluster list will be updated immediately\n")); } printf(MSGSTR(CLSTAT_PREV_SCRN,"\n\n\nPress [ENTER] to return to the previous screen\n")); gets(any_act); } int compareNetifs(pNetif1, pNetif2) struct cl_netif *pNetif1, *pNetif2; { int i; for (i = 0; i < CL_MAXNETIFS; i++) { if (pNetif1[i].cli_state != pNetif2[i].cli_state || (pNetif1[i].cli_addr.sin_addr.s_addr != pNetif2[i].cli_addr.sin_addr.s_addr) || (memcmp (&(((struct sockaddr_in6 *)&(pNetif1[i].cli_addr6))->sin6_addr), &(((struct sockaddr_in6 *)&(pNetif1[i].cli_addr6))->sin6_addr), sizeof (struct in6_addr))) || strcmp(pNetif1[i].cli_name, pNetif2[i].cli_name)) return 1; } return 0; } int compareNodemap(pNodemap1, pNodemap2) struct cl_node *pNodemap1, *pNodemap2; { int i; for (i = 0; i < CL_MAXNODES; i++) { if (pNodemap1[i].cln_state != pNodemap2[i].cln_state) return 1; } return 0; } /* * Name: compareGroupmap * * Description: compares the contents of 2 cl_group struct arrays * * Arguments: pointer to the cl_group(s) to be compared * * Return: 0 - maps are equal * 1 - maps are not equal * * Global Data Affected: NONE */ int compareGroupmap(struct cl_group *pGroupmap1, struct cl_group *pGroupmap2) { int i; for (i = 0; i < CL_MAXGROUPS; i++) { if (pGroupmap1[i].clg_group_id != pGroupmap2[i].clg_group_id) return 1; } return 0; } /* * Name: copyNodemap * * Description: Copies a nodemap from source to dest. This routine assumes * storage has already been allocated for both nodemaps. copyNodemap differs * from bcopy in that it does not copy the pointer to interfaces, but rather * the interfaces themselves. * * Arguments: pointer to the source and destination maps * * Return: NONE * * Global Data Affected: NONE */ void copyNodemap(pSource, pDest) struct cl_node *pSource, *pDest; { int i; for (i = 0; i < CL_MAXNODES; i++) { pDest[i].cln_clusterid = pSource[i].cln_clusterid; pDest[i].cln_nodeid = pSource[i].cln_nodeid; strcpy(pDest[i].cln_nodename, pSource[i].cln_nodename); pDest[i].cln_state = pSource[i].cln_state; pDest[i].cln_nif = pSource[i].cln_nif; bcopy (pSource[i].cln_if, pDest[i].cln_if, sizeof (struct cl_netif) * CL_MAXNETIFS); } } /* * Name: notOfflineGroupState * * Description: Given a group pointer and a node id, search all the nodes * in the group for the node id. * * Arguments: pointer to the group struct and a node id * * Return: 0 - if the node is not in the group or * the node is in the group but the state is offline * 1 - the node is part of the group and the state is not offline * */ int notOfflineGroupState(struct cl_group *pGroup, int node_id) { int i; for (i = 0; i < pGroup->clg_num_nodes; i++) { if (pGroup->clg_node_ids[i] == node_id && pGroup->clg_node_states[i] > CL_RGNS_INVALID && pGroup->clg_node_states[i] <= CL_RGNS_UNMANAGED_SECONDARY_STATE && pGroup->clg_node_states[i] <= CL_RGNS_OFFLINE_DUE_TO_TARGET_OFFLINE && pGroup->clg_node_states[i] != CL_RGNS_OFFLINE) return(TRUE); } return(FALSE); } /* * Name: resetClustermap * * Description: "clears" the entries in a cluster map to default values * * Arguments: pointer to the cl_cluster map * * Return: NONE * * Global Data Affected: NONE */ void resetClustermap(pClustermap) struct cl_cluster *pClustermap; { int i; for (i = 0; i < CL_MAXCLUSTERS; i++) { pClustermap[i].clc_clusterid = -1; pClustermap[i].clc_state = CLS_INVALID; pClustermap[i].clc_substate = CLS_INVALID; memset(pClustermap[i].clc_primary, '\0', CL_MAXNAMELEN); memset(pClustermap[i].clc_name, '\0', CL_MAXNAMELEN); pClustermap[i].clc_number_of_nodes = 0; pClustermap[i].clc_number_of_groups = 0; pClustermap[i].clc_number_of_networks = 0; pClustermap[i].clc_number_of_sites = 0; } } /* * Name: resetNodemap * * Description: "clears" the entries in a node map to default values * * Arguments: pointer to the cl_node map * * Return: NONE * * Global Data Affected: NONE */ void resetNodemap(pNodemap) struct cl_node *pNodemap; { int i; for (i = 0; i < CL_MAXNODES; i++) { pNodemap[i].cln_clusterid = -1; pNodemap[i].cln_nodeid = -1; memset(pNodemap[i].cln_nodename, '\0', CL_MAXNAMELEN); pNodemap[i].cln_state = CLS_INVALID; pNodemap[i].cln_nif = 0; memset (pNodemap[i].cln_if, 0, sizeof (struct cl_netif) * CL_MAXNETIFS); } } /* * Name: resetGroupmap * * Description: "clears" the entries in a resource group map to default values * * Arguments: pointer to the cl_group map * * Return: NONE * * Global Data Affected: NONE */ void resetGroupmap(struct cl_group *groupMap) { int i; for (i = 0; i < CL_MAXGROUPS; i++) { groupMap[i].clg_clusterid = -1; groupMap[i].clg_group_id = -1; memset(groupMap[i].clg_name, '\0', CL_MAXNAMELEN); } } /* * Name: javaGroupInfo * * Description: Shows resource group info along with building a javascript * which shows additional data * * Arguments: resource group struct, the node map and a node id * * Return: NONE * * Global Data Affected: NONE */ void javaGroupInfo(struct cl_group *group_map, struct cl_node *node_map, int nodeid) { int i, rc=0; #ifdef CLINFO_ODM_LOOKUP char *classname = NULL; char crit[128]=""; char *odmdir = "/etc/es/objrepos"; char *field = NULL; char *group = NULL; int count; struct HACMPresource *info; struct HACMPgroup *group_info; CLASS_SYMBOL class; #endif /* begin by printing the info we know - group name and id */ printf( "\n"); printf( "Resource Group:\n"); printf( "\n" "Resource Group Information" "

" "Resource Group Information" "

" /* table row */ "" "\n", group_map->clg_name, group_map->clg_group_id); #ifdef CLINFO_ODM_LOOKUP /* The javascript produced to display extended RG information does * not work correctly in IE, Mozilla, Netscape, or Firefox. Also, * logic used to determine the information to display is incorrect, * because it assumes that only one cluster is being monitored. * Because this code is non-essential, I have used preprocessor * directives to exclude it from being built. This code can be * corrected in a future release. */ /* now we will print the rest of the information - either from the odm */ /* or from the clinfo data */ odm_set_path(odmdir); sprintf(crit, "id = %d", group_map->clg_group_id); classname = "HACMPgroup"; group_info = (struct HACMPgroup *)odmget(classname, crit, &count); if (count > 0) { sprintf(crit, "group = %s", group_info->group); classname = "HACMPresource"; count = 0; info = (struct HACMPresource *)odmget(classname, crit, &count); /* we have the group info from odm and the list of resources - */ /* start printing */ /* RG startup policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_startup_policy)); /* RG Fallover Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_fallover_policy)); /* Fallback Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_fallback_policy)); /* Site Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_site_policy)); printf( /* table row */ "" "\n", group_info->nodes); for (i = 0; i < count; i++) { printf( "" "\n", info[i].name, info[i].value); } } /* we have odm info */ else { #endif /* if here, we were not able to read from the odm - all we can */ /* display is the info available from clinfo */ /* RG startup policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_startup_policy)); /* RG Fallover Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_fallover_policy)); /* Fallback Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_fallback_policy)); /* Site Policy */ printf( "" "\n", resourcePolicyStr(group_map->clg_site_policy)); /* nodes in the group are stored by id - convert the node list */ printf( /* table row */ "" "\n", nodeArrayStr(node_map, group_map->clg_node_ids, group_map->clg_num_nodes)); #ifdef CLINFO_ODM_LOOKUP } #endif /* end of the javascript table */ printf( "
" "" "Name / ID:" "  %s  (%d)" "
" "" "Startup Policy:" "  %s  " "
" "" "Fallover Policy:" "  %s  " "
" "" "Fallback Policy:" "  %s  " "
" "" "Site Policy:" "  %s  " "
" "" "Node list:" "  %s" "
" "" "%s:" "  %s" "
" "" "Startup Policy:" "  %s  " "
" "" "Fallover Policy:" "  %s  " "
" "" "Fallback Policy:" "  %s  " "
" "" "Site Policy:" "  %s  " "
" "" "Node list:" "  %s" "
';}\">" "%s
\n", group_map->clg_name); printf( "State:\n"); printf( "
%s
\n", resourceStateColor(group_map, nodeid), resourceStateStr(group_map, nodeid)); } /* * Name: nodeArrayStr * * Description: Generates a string with the names of all the nodes in the group * * Arguments: Node map, list of nodes in the group, and number of nodes * * Return: char * buf - buffer in which to store formatted node string * * Global Data Affected: NONE */ char * nodeArrayStr(struct cl_node *pNodemap, int *group_node_ids, int num_nodes) { int i,j; /* use MAXNODES here because CL_MAXNODES maps to a variable value */ static char ret_str[MAXNODES][CL_MAXNAMELEN]; memset(ret_str, 0, CL_MAXNODES * CL_MAXNAMELEN); for (i=0; i 0) { infop = malloc(listinfo.num * class->structsize); if(infop) { bcopy(odmp, infop, listinfo.num * class->structsize); *countp = listinfo.num; } else { perror("odmget: malloc"); } } if(odmp) odm_free_list(odmp, &listinfo); odm_close_class(class); return(infop); } #endif