/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* (C) COPYRIGHT International Business Machines Corp. 1996,2019 */ /* 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 */ /* @(#)44 1.3 src/rsct/pem/emtools/emapi_test/emapi_ex/emapi_v02_ex04.c, emtools, rsct_rady, rady2035a 6/30/98 10:47:45 */ #include #include #include #include #include #include #define HA_EM_VERSION 2 #include /* * emapi_v02_ex04.c * * This program presents an example of using the Event Manager Application * Programming Interface (EMAPI). The program uses the EMAPI to obtain * the definition of some resource variables. * * This program can be compiled with the following command: * * cc -O emapi_v02_ex04.c -o emapi_v02_ex04 -lha_em */ /* * The following array contains query requests that will be sent to the * EMAPI. Each array element is of type struct ha_em_rb_query, which is * defined by the EMAPI. Each element specifies a class, a resource * variable, and a resource ID. * * Request 1 requests the definitions of resource variables in the * IBM.PSSP.Prog class. * * Request 2 requests the definitions of resource variables in the * IBM.PSSP.SP_HW class whose resource variable names start with * IBM.PSSP.SP_HW.Node. * * Request 3 requests the definitions of resource variables in all * classes whose resource IDs include a resource ID element * named CPU. */ static struct ha_em_rb_query qry_array[] = { {"IBM.PSSP.Prog", "", "*"}, /* Request 1 */ {"IBM.PSSP.SP_HW", "IBM.PSSP.SP_HW.Node", "*"}, /* Request 2 */ {"", "", "CPU;*"} /* Request 3 */ }; static int qry_cnt = sizeof qry_array / sizeof qry_array[0]; /* * Function prototypes for internal functions. */ static void setup_signals(void); static int start_session(void); static ha_em_qid_t send_defn_request(int sess_fd, struct ha_em_rb_query *qry_array, int qry_cnt); static int recv_defn_reply(int sess_fd, ha_em_qid_t qid); static int process_response_query(ha_em_qid_t qid, struct ha_em_rsp_blk *rsp_blk); static int process_response_qerr(ha_em_qid_t qid, struct ha_em_rsp_blk *rsp_blk); static void end_session(int sess_fd); /* * The main() function calls functions to initialize the program, establish * an EMAPI session, send query requests, wait for and process Event Manager * responses, and terminate the EMAPI session. */ int main(int argc, char **argv) { int sess_fd; /* Session file descriptor */ ha_em_qid_t qid; /* Query identifier */ int qend; /* Query is finished */ setup_signals(); /* Set signal dispositions */ sess_fd = start_session(); /* Start EMAPI session */ qid = send_defn_request(sess_fd, qry_array, qry_cnt); /* Send query request */ /* * Receive query replies until all replies have been received. */ while ((qend = recv_defn_reply(sess_fd, qid)) == 0) { /* Nothing to do inside the loop */ } end_session(sess_fd); /* End EMAPI session */ return 0; } /* * The setup_signals() function initializes the disposition of a signal. * * The disposition of the SIGPIPE signal is set such that the signal is * ignored. When a process writes to a pipe or connection-oriented socket for * which there is no reader, the SIGPIPE signal is delivered to the process. * The default disposition for SIGPIPE is to kill the receiving process. If * SIGPIPE is ignored, the SIGPIPE signal does not kill the process, and the * system call used to write to the pipe or connection-oriented socket sets * errno to EPIPE and returns an error indication. It is recommended that * clients of the EMAPI ignore the SIGPIPE signal, since the EMAPI uses * connection-oriented sockets to communicate with the Event Manager. */ static void setup_signals(void) { struct sigaction sa; sa.sa_handler = SIG_IGN; /* SIGPIPE to be ignored */ sigemptyset(&sa.sa_mask); /* No signals to mask off */ sa.sa_flags = 0; /* No flags needed */ if (sigaction(SIGPIPE, &sa, NULL) == -1) { /* Change SIGPIPE disposition*/ perror("sigaction(SIGPIPE)"); exit(1); } return; } /* * The start_session() function establishes a session with the EMAPI by * calling the EMAPI routine ha_em_start_session(). If a session cannot be * established, the program is terminated. */ static int start_session(void) { int sess_fd; /* Session file descriptor */ struct ha_em_err_blk errb; /* EMAPI error block */ /* * Since no specific partition name is passed to the * ha_em_start_session() routine, it attempts to establish a session * with the default partition. The routine returns a file * descriptor with which the session can be used. */ sess_fd = ha_em_start_session(HA_EM_DOMAIN_SP, "", &errb); /* * If ha_em_start_session() indicates a session could not be established, * print the error information returned by the routine, and exit the * program. */ if (sess_fd == -1) { fprintf(stderr, "ha_em_start_session() returned EM errno %d:\n%s", errb.em_errno, errb.em_errmsg); exit(1); } return sess_fd; /* Return session fd */ } /* * The send_defn_request() function uses the EMAPI routine * ha_em_send_command() to send the query defined resource variables requests * specified by the qry_array and qry_cnt parameters. */ static ha_em_qid_t send_defn_request(int sess_fd, struct ha_em_rb_query *qry_array, int qry_cnt) { size_t alloc_size; /* Size of memory to allocate */ struct ha_em_cmd_blk *cmd_blk; /* Pointer to command block */ struct ha_em_err_blk errb; /* EMAPI error block */ int rc; /* Return code */ ha_em_qid_t qid; /* Query identifier */ /* * Allocate enough memory to hold the command block to be given to the * EMAPI. The ha_em_cmd_blk structure contains one ha_em_rb_query * structure. Additional space must be allocated when more than one * query is to be made. */ alloc_size = sizeof(struct ha_em_cmd_blk) + ((qry_cnt - 1) * sizeof(struct ha_em_rb_query)); if ((cmd_blk = malloc(alloc_size)) == NULL) { perror("malloc()"); exit(1); } /* * Fill in command block header, specifying number of elements in * em_rb_query array, command, and subcommand. Indicate a callback * routine will not be used to receive the responses. */ cmd_blk->em_cmd_num_elem = qry_cnt; cmd_blk->em_cmd = HA_EM_CMD_QUERY; cmd_blk->em_subcmd = HA_EM_SCMD_QDEF; cmd_blk->em_qcb = NULL; cmd_blk->em_qcb_arg = NULL; /* * Copy the array of query requests into the command block. */ memcpy(cmd_blk->em_res_blk.em_rb_query, qry_array, qry_cnt * sizeof(struct ha_em_rb_query)); /* * Send the command. A more elaborate program might check for the * HA_EM_ECONNLOST Event Manager error number when an error is * returned, and attempt to restart the session. But, this program * just terminates if ha_em_send_command() detects a lost connection. */ rc = ha_em_send_command(sess_fd, cmd_blk, &errb); if (rc == -1) { fprintf(stderr, "ha_em_send_command() returned EM errno %d:\n%s", errb.em_errno, errb.em_errmsg); exit(1); } /* * Save the query identifier assigned to the query request just sent. */ qid = cmd_blk->em_qid; free(cmd_blk); /* Free the allocated command block. */ return qid; /* Return the query identifier */ } /* * The recv_defn_reply() function processes an Event Manager response * in the specified EMAPI session. First, ha_em_receive_response() is called * to receive the response. If ha_em_receive_response() returns an error * the program is terminated. The ha_em_receive_response() function may * indicate that there really isn't any response for the EMAPI client to * process at this time. In that case, this function just returns. If a * response has been received, it is processed depending on what type of * response it is. * * This function returns 0 if all query responses have not been received yet. * If all query responses have been received, 1 is returned. */ static int recv_defn_reply(int sess_fd, ha_em_qid_t qid) { struct ha_em_rsp_blk *rsp_blk; /* Pointer to the response block */ int rc; /* Return code */ struct ha_em_err_blk errb; /* Event Manager error block */ int qend; /* Query end flag */ /* * Receive response from session, if there is one to receive. */ rc = ha_em_receive_response(sess_fd, &rsp_blk, &errb); if (rc == -1) { /* * Some error has occurred receiving a response; terminate the * program. A more elaborate program might check for the * HA_EM_ECONNLOST Event Manager error number when an error is * returned, and attempt to restart the session. But, this program * just terminates if ha_em_receive_response() detects a lost * connection. */ fprintf(stderr, "ha_em_receive_response() returned EM errno %d:\n%s", errb.em_errno, errb.em_errmsg); exit(1); } /* * If the ha_em_receive_response() routine returned zero, * there is no response for the EMAPI client (this program) to process * at this time. The response may have been for the EMAPI itself, or * a full response may not be available yet. Just return. */ if (rc == 0) { return 0; /* Return indicating query is not ended */ } /* * A response for the EMAPI client (this program) has been returned. * The response buffer is pointed to by the rsp_blk variable. Appropriate * processing for the response depends on the command type. */ switch (rsp_blk->em_cmd) { case HA_EM_CMD_QUERY: /* Query response */ qend = process_response_query(qid, rsp_blk); break; case HA_EM_CMD_QERR: /* Query error response */ qend = process_response_qerr(qid, rsp_blk); break; default: /* Unexpected response */ fprintf(stderr, "Program received unexpected command " "response: %d.\n", rsp_blk->em_cmd); exit(1); break; } /* * The EMAPI client (this program) must free the memory associated with * the returned response block when it is no longer needed. */ free(rsp_blk); return qend; } /* * The process_response_query() function processes query responses from the * Event Manager. Several points should be kept in mind: * * - The response block may contain multiple query responses. The * number of responses included in the response block is given in * the response block header. * * - An query response may be an error response. Such a response * may indicate an error of a temporary nature. * * - This routine compares the query identifier in the response block * with the query identifier assigned to the request sent by * this program to the EMAPI. This should not really be necessary. * If the program had sent multiple query requests to the EMAPI, * through multiple calls to ha_em_send_command(), the query identifiers * in the response blocks could be used to associate responses with * requests. * * - Multiple response blocks may be associated with one request block. * The response to a query request is not complete until a response * block is received with the em_qend field set to a non-zero value. */ static int process_response_query(ha_em_qid_t qid, struct ha_em_rsp_blk *rsp_blk) { struct ha_em_rpb_qdef *qp; /* Pointer to query response */ struct ha_em_rpb_qdef *last_qp; /* Beyond last query response */ /* * Check query identifier in response block. */ if (rsp_blk->em_qid != qid) { fprintf(stderr, "Query response block contains unexpected " "query identifier: %d.\n", rsp_blk->em_qid); exit(1); } /* * Look at all the response elements in the response block. */ qp = rsp_blk->em_resp_blk.em_rpb_qdef; last_qp = qp + rsp_blk->em_rsp_num_resp; for ( ; qp < last_qp; qp++) { printf("============================================================" "\n\n"); /* * Check for error code. */ if (qp->em_errnum != 0) { printf("Query response for class \"%s\", " "resource variable \"%s\", resource ID \"%s\" " "unexpectedly contains an error (%d, %d).\n\n", qp->em_class, qp->em_name, qp->em_rsrc_ID, qp->em_generr, qp->em_specerr); continue; } /* * Print definition of a resource variable. */ printf("Resource Variable Name: \"%s\"\n" "Variable Value Type: %s\n" "Variable Data Type: %s\n" "Variable SBS Format: \"%s\"\n" "Variable Initial Value: \"%s\"\n" "Variable Class: \"%s\"\n" "Resource ID: \"%s\"\n" "PTX Name: \"%s\"\n" "Default Expression: \"%s\"\n" "Locator: \"%s\"\n" "\n" "Variable Description\n" "--------------------\n" "%s\n" "\n" "Resource ID Description\n" "-----------------------\n" "%s\n" "\n" "Event Description\n" "-----------------\n" "%s\n" "\n", qp->em_name, qp->em_value_type == ha_emVTcounter ? "Counter" : qp->em_value_type == ha_emVTquantity ? "Quantity" : qp->em_value_type == ha_emVTstate ? "State" : "Unknown", qp->em_data_type == ha_emDTlong ? "long" : qp->em_data_type == ha_emDTfloat ? "float" : qp->em_data_type == ha_emDTsbs ? "SBS" : "Unknown", qp->em_sbs_format, qp->em_init_value, qp->em_class, qp->em_rsrc_ID, qp->em_ptx_name, qp->em_dflt_expr, qp->em_locator, qp->em_descrp, qp->em_rsrc_ID_descrp, qp->em_event_descrp); } return rsp_blk->em_qend; } /* * The process_response_qerr() function processes query error * responses. */ static int process_response_qerr(ha_em_qid_t qid, struct ha_em_rsp_blk *rsp_blk) { struct ha_em_rpb_qerr *error_p; /* Pointer to error response */ struct ha_em_rpb_qerr *last_error_p; /* Beyond last error response*/ /* * Check query identifier in response block. */ if (rsp_blk->em_qid != qid) { fprintf(stderr, "Query response block contains unexpected " "query identifier: %d.\n", rsp_blk->em_qid); exit(1); } error_p = rsp_blk->em_resp_blk.em_rpb_qerr; last_error_p = error_p + rsp_blk->em_rsp_num_resp; for ( ; error_p < last_error_p; error_p++) { printf("============================================================" "\n\n"); /* * Print error information for a resource variable. */ printf("Resource Variable Name: \"%s\"\n" "Variable Class: \"%s\"\n" "Resource ID: \"%s\"\n" "General Error: %d\n" "Specific Error: %d\n" "Additional Error Info: %d\n", error_p->em_name, error_p->em_class, error_p->em_rsrc_ID, error_p->em_generr, error_p->em_specerr, error_p->em_errinfo); } return rsp_blk->em_qend; } /* * The end_session() function terminates a session with the EMAPI by * calling the EMAPI routine ha_em_end_session(). */ static void end_session(int sess_fd) { struct ha_em_err_blk errb; if (ha_em_end_session(sess_fd, &errb) == -1) { fprintf(stderr, "ha_em_end_session() returned EM errno %d:\n%s", errb.em_errno, errb.em_errmsg); exit(1); } return; }