1
0
Files
irix-657m-src/eoe/cmd/fcman/fcagent_th.c
2022-09-29 17:59:04 +03:00

666 lines
19 KiB
C

#include "options.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdarg.h> /* For varargs */
#include <stdlib.h> /* For string conversion routines */
#include <string.h>
#include <bstring.h>
#include <ctype.h> /* For character definitions */
#include <errno.h>
#include <syslog.h>
#include <sys/signal.h> /* for UNIX signals */
#include <sys/wait.h>
#include <sys/socket.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#define XDR_SHORTCUT
#include "debug.h"
#include "fcagent.h"
#include "fcagent_vers.h"
#include "fcagent_structs.h"
#include "fcagent_rpc.h"
#include "usrsignal.h"
void th_priv_cleanup();
void th_fatal(char *format, ...);
void th_signal_handler(int sig);
int th_callout(ca_t ca);
extern void agent_prog_1(struct svc_req *rqstp, SVCXPRT *transp);
char *frutype2str(uint type);
char *stat2str(uint type);
usr_sigaction_t th_actions[] =
{
{SIGINT, th_signal_handler, SA_RESTART},
{SIGHUP, th_signal_handler, SA_RESTART},
{SIGSOFTKILL, th_signal_handler, SA_RESTART},
{NULL, NULL, NULL}
};
/*
******************************************************************************
* th_priv_cleanup()
* Thread cleanup routine - must be called prior to exiting from a thread
******************************************************************************
*/
void th_priv_cleanup()
{
uint npid = upid2npid(getpid());
DBG(D_THREAD, "th_priv_cleanup() : Thread %d : CLEANING UP\n", npid);
}
/*
******************************************************************************
* th_fatal()
******************************************************************************
*/
void th_fatal(char *format, ...)
{
uint npid = upid2npid(getpid());
va_list ap;
char tmpString[200];
va_start(ap, format);
vsprintf(tmpString, format, ap);
printf("THREAD FATAL : NPID = 0x%08x : %s\n", npid, tmpString);
va_end(ap);
th_priv_cleanup();
exit(1);
}
/*
******************************************************************************
* th_signal_handler()
******************************************************************************
*/
void th_signal_handler(int sig)
{
int npid = upid2npid(getpid());
switch(sig) {
case SIGINT:
DBG(D_SIGNAL, "Thread NPID = %d received a SIGINT\n", npid);
break;
case SIGHUP:
DBG(D_SIGNAL, "Thread NPID = %d received a SIGHUP\n", npid);
break;
case SIGSOFTKILL:
DBG(D_SIGNAL, "Thread NPID = %d received a SIGSOFTKILL(%d)\n", npid, SIGSOFTKILL);
th_priv_cleanup();
exit(0);
break;
default:
DBG(D_SIGNAL, "Thread NPID = %d received a unknown signal [%d]\n", npid, sig);
}
}
/*
******************************************************************************
* th_callout() - execv a callout function
******************************************************************************
*/
int th_callout(ca_t ca)
{
char *argv[15];
char tmpString[1024];
char *p = tmpString;
sigset_t set, oset;
pid_t pid;
int status, rc;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, &oset);
pid = fork();
if (pid == -1)
th_fatal("fork() failed : %s\n", strerror(errno));
else
if (pid == 0) {
bzero(argv, sizeof(argv));
argv[0] = ca->ca_name;
argv[1] = ca->ca_hostname;
argv[2] = ca->ca_typename;
sprintf(tmpString, "%s", ctime(&ca->ca_timestamp)); argv[3] = p; p[strlen(p)-1] = '\0'; p += strlen(p) + 1;
sprintf(p, "%d", ca->ca_ch_id); argv[4] = p; p += strlen(p) + 1;
sprintf(p, "%d", ca->ca_encl_id); argv[5] = p; p += strlen(p) + 1;
sprintf(p, "%s", frutype2str(ca->ca_fru_type_id)); argv[6] = p; p += strlen(p) + 1;
sprintf(p, "%d", ca->ca_fru_id); argv[7] = p; p += strlen(p) + 1;
sprintf(p, "%s", stat2str(ca->ca_from_stat)); argv[8] = p; p += strlen(p) + 1;
sprintf(p, "%s", stat2str(ca->ca_to_stat)); argv[9] = p; p += strlen(p) + 1;
if (execvp(argv[0], argv) == -1)
exit(errno);
}
else {
wait(&status);
if (WIFSTOPPED(status)) {
th_fatal("th_callout() failed: Received a SIGCHLD (STOPPED).\n");
}
else
if (WIFEXITED(status)) {
rc = WEXITSTATUS(status);
if (rc) {
DBG(D_CO, "FCAGENT callout (%s) failed: %s\n", ca->ca_name, strerror(rc));
syslog(LOG_ERR, "FCAGENT callout (%s) failed: %s\n", ca->ca_name, strerror(rc));
}
return(rc);
}
else
if (WIFSIGNALED(status)) {
rc = WTERMSIG(status);
if (rc) {
DBG(D_CO, "FCAGENT callout (%s) terminated on signal %d\n", ca->ca_name, rc);
syslog(LOG_ERR, "FCAGENT callout (%s) terminated on signal %d\n", ca->ca_name, rc);
}
return(-1);
}
else
return(0);
}
/* NOTREACHED */
}
/*
******************************************************************************
* EVENT HANDLER THREAD
******************************************************************************
*/
void event_handler_proc(void *arg)
{
int npid = (int) arg;
sigset_t oset, set;
ca_struct_t ca;
event_t ev;
char hostname[MAXHOSTNAMELEN];
if (install_signal_handlers(th_actions) == -1)
th_fatal("install_signal_handlers() failed : %s\n", strerror(errno));
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
if (sigprocmask(SIG_UNBLOCK, &set, &oset))
th_fatal("sigprocmask() failed : %s\n", strerror(errno));
if (gethostname(hostname, MAXHOSTNAMELEN))
th_fatal("gethostname() failed: %s\n", strerror(errno));
while (1) {
ev = ev_dequeue();
switch (ev->ev_type) {
case EVT_TYPE_INFO:
ca.ca_typename = "INFO";
syslog(LOG_INFO, "FRU state change: %s #%d in enclosure %d on channel %d: %s --> %s\n",
frutype2str(ev->ev_elem_type),
ev->ev_elem_id,
ev->ev_encl_id,
ev->ev_ch_id,
stat2str(ev->ev_old_status),
stat2str(ev->ev_new_status));
break;
case EVT_TYPE_CONFIG:
ca.ca_typename = "RECONFIG";
syslog(LOG_NOTICE, "FRU reconfiguration: %s #%d in enclosure %d on channel %d: %s --> %s\n",
frutype2str(ev->ev_elem_type),
ev->ev_elem_id,
ev->ev_encl_id,
ev->ev_ch_id,
stat2str(ev->ev_old_status),
stat2str(ev->ev_new_status));
break;
case EVT_TYPE_FAILURE:
ca.ca_typename = "FAILURE";
syslog(LOG_CRIT, "FRU failure: %s #%d in enclosure %d on channel %d\n",
frutype2str(ev->ev_elem_type),
ev->ev_elem_id,
ev->ev_encl_id,
ev->ev_ch_id);
syslog(LOG_CRIT, "");
break;
}
ca.ca_name = CFG->ac_stat_change_co;
ca.ca_hostname = hostname;
ca.ca_timestamp = ev->ev_timestamp;
ca.ca_ch_id = ev->ev_ch_id;
ca.ca_encl_id = ev->ev_encl_id;
ca.ca_fru_type_id = ev->ev_elem_type;
ca.ca_fru_id = ev->ev_elem_id;
ca.ca_from_stat = ev->ev_old_status;
ca.ca_to_stat = ev->ev_new_status;
th_callout(&ca);
}
}
/*
******************************************************************************
* RCP REQUEST HANDLER THREAD
******************************************************************************
*/
void request_handler_proc(void *arg)
{
int npid = (int) arg;
register SVCXPRT *transp;
if (install_signal_handlers(th_actions) == -1)
th_fatal("install_signal_handlers() failed : %s\n", strerror(errno));
{
sigset_t oset, set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
if (sigprocmask(SIG_UNBLOCK, &set, &oset))
th_fatal("sigprocmask() failed : %s\n", strerror(errno));
}
(void) pmap_unset(AGENT_PROG, AGENT_VERS);
#if 0
transp = svcudp_create(RPC_ANYSOCK);
if (transp == NULL) {
fprintf(stderr, "cannot create udp service.");
exit(1);
}
if (!svc_register(transp, AGENT_PROG, AGENT_VERS, agent_prog_1, IPPROTO_UDP)) {
fprintf(stderr, "unable to register (AGENT_PROG, AGENT_VERS, udp).");
exit(1);
}
#endif
#if 1
transp = svctcp_create(RPC_ANYSOCK, 0, 0);
if (transp == NULL) {
fprintf(stderr, "cannot create tcp service.");
exit(1);
}
if (!svc_register(transp, AGENT_PROG, AGENT_VERS, agent_prog_1, IPPROTO_TCP)) {
fprintf(stderr, "unable to register (AGENT_PROG, AGENT_VERS, tcp).");
exit(1);
}
#endif
svc_run();
fprintf(stderr, "svc_run returned");
exit(1);
/* NOTREACHED */
}
/*
******************************************************************************
* agent_get_vers_1() - string AGENT_GET_VERS(void) = 1;
******************************************************************************
*/
char **agent_get_vers_1()
{
static char *VERSION=VERS;
return(&VERSION);
}
/*
******************************************************************************
* agent_get_config_1() - cfg_t AGENT_GET_CONFIG(void) = 2;
******************************************************************************
*/
cfg_t *agent_get_config_1()
{
static cfg_t *config = NULL;
int ch_count, encl_count;
channel_e_t ch;
encl_ref_t eref;
int i,j;
if (config == NULL) {
/*
* Walk down channel list and count the number available.
*/
for (ch_count = 0, ch = CH_HEAD; ch; ++ch_count, ch = ch->next)
;
config = calloc(1, sizeof(cfg_t));
config->cfg_t_len = ch_count;
if ((config->cfg_t_val = calloc(ch_count, sizeof(ch_cfg_t))) == NULL)
th_fatal("agent_get_config_1() failed: %s\n", strerror(errno));
for (i = 0, ch = CH_HEAD; i < ch_count; ++i, ch = ch->next) {
config->cfg_t_val[i].ch_id = ch->id;
}
/*
* For each channel walk down the enclosure reference list to see
* if anything has changed
*/
for (i = 0, ch = CH_HEAD; i < ch_count; ++i, ch = ch->next) {
for (encl_count = 0, eref = ch->encl_ref_head; eref; ++encl_count, eref = eref->next)
;
if (config->cfg_t_val[i].encl_id_val && config->cfg_t_val[i].encl_id_len != encl_count) {
free(config->cfg_t_val[i].encl_id_val);
free(config->cfg_t_val[i].stat_gencode_val);
config->cfg_t_val[i].encl_id_val = NULL;
config->cfg_t_val[i].encl_id_len = 0;
config->cfg_t_val[i].stat_gencode_val = NULL;
config->cfg_t_val[i].stat_gencode_len = 0;
}
if (config->cfg_t_val[i].encl_id_val == NULL) {
config->cfg_t_val[i].encl_id_len = encl_count;
if ((config->cfg_t_val[i].encl_id_val = calloc(encl_count, sizeof(u_int))) == NULL)
th_fatal("agent_get_config_1() failed: %s\n", strerror(errno));
config->cfg_t_val[i].stat_gencode_len = encl_count;
if ((config->cfg_t_val[i].stat_gencode_val = calloc(encl_count, sizeof(u_int))) == NULL)
th_fatal("agent_get_config_1() failed: %s\n", strerror(errno));
}
for (j = 0, eref = ch->encl_ref_head; j < encl_count; ++j, eref = eref->next) {
config->cfg_t_val[i].encl_id_val[j] = eref->encl->wwn;
config->cfg_t_val[i].stat_gencode_val[j] = eref->encl->status_gen_code;
}
}
}
return(config);
}
/*
******************************************************************************
* agent_get_status_1() - enc_stat_t AGENT_GET_STATUS(enc_addr_t) = 3;
******************************************************************************
*/
enc_stat_t *agent_get_status_1(enc_addr_t *in_addr)
{
static enc_stat_t *out_stat;
channel_e_t ch;
encl_e_t encl;
int i;
ch = agent_find_ch_by_cid(in_addr->ch_id);
if (ch == NULL)
th_fatal("agent_get_status_1() failed: Cannot find channel %d\n", in_addr->ch_id);
encl = agent_find_encl_by_eid(ch, in_addr->encl_id);
if (encl == NULL)
th_fatal("agent_get_status_1() failed: Cannot find enclosure %d on channel %d\n",
in_addr->encl_id, in_addr->ch_id);
/*
* Free structs from previous query
*/
if (out_stat) {
free(out_stat->drv_val);
free(out_stat->fan_val);
free(out_stat->ps_val);
free(out_stat->lcc_val);
free(out_stat);
out_stat = NULL;
}
out_stat = calloc(1, sizeof(enc_stat_t));
out_stat->encl_id = in_addr->encl_id;
out_stat->encl_status = encl->status;
out_stat->encl_phys_id = encl->phys_id;
bcopy(encl->vid, out_stat->encl_vid, sizeof(encl->vid));
bcopy(encl->pid, out_stat->encl_pid, sizeof(encl->pid));
bcopy(encl->prl, out_stat->encl_prl, sizeof(encl->prl));
bcopy(&encl->wwn, out_stat->encl_wwn, sizeof(encl->wwn));
out_stat->encl_lccstr_len = encl->lcc_str_len;
out_stat->encl_lccstr_val = encl->lcc_str;
out_stat->drv_len = encl->drv_count;
out_stat->drv_val = calloc(encl->drv_count, sizeof(drv_stat_t));
for (i = 0; i < encl->drv_count; ++i) {
out_stat->drv_val[i].drv_stat_t_len = sizeof(drv_e_struct_t);
out_stat->drv_val[i].drv_stat_t_val = (char *)&encl->drv[i];
}
out_stat->ps_len = encl->ps_count;
out_stat->ps_val = calloc(encl->ps_count, sizeof(ps_stat_t));
for (i = 0; i < encl->ps_count; ++i) {
out_stat->ps_val[i].ps_stat_t_len = sizeof(ps_e_struct_t);
out_stat->ps_val[i].ps_stat_t_val = (char *)&encl->ps[i];
}
out_stat->fan_len = encl->fan_count;
out_stat->fan_val = calloc(encl->fan_count, sizeof(fan_stat_t));
for (i = 0; i < encl->fan_count; ++i) {
out_stat->fan_val[i].fan_stat_t_len = sizeof(fan_e_struct_t);
out_stat->fan_val[i].fan_stat_t_val = (char *)&encl->fan[i];
}
out_stat->lcc_len = encl->lcc_count;
out_stat->lcc_val = calloc(encl->lcc_count, sizeof(lcc_stat_t));
for (i = 0; i < encl->lcc_count; ++i) {
out_stat->lcc_val[i].lcc_stat_t_len = sizeof(lcc_e_struct_t);
out_stat->lcc_val[i].lcc_stat_t_val = (char *)&encl->lcc[i];
}
return(out_stat);
}
/*
******************************************************************************
* agent_set_drv_remove_1() - unsigned int AGENT_SET_DRV_REMOVE(drive_op_t) = 4;
******************************************************************************
*/
int *agent_set_drv_remove_1(drive_op_t *dop)
{
channel_e_t ch;
u_int ch_id = dop->ch_id;
u_int op = dop->op;
fcid_bitmap_t fcid_bm = (fcid_bitmap_t)dop->fcid_bm.fcid_t_val;
int i;
char hostname[MAXHOSTNAMELEN];
ca_struct_t ca;
static int result=0;
if (__debug & D_ESI) {
printf("DRV_REMOVE: CH = %d, OP = %d, FCIDS = ", ch_id, op);
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i))
printf("%d ", i);
printf("\n");
}
if (gethostname(hostname, MAXHOSTNAMELEN))
th_fatal("gethostname() failed: %s\n", strerror(errno));
/*
* Execute pre-remove callout for all devices to be removed
*/
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i)) {
ca.ca_name = CFG->ac_preremovalco;
ca.ca_typename = "PRE-REMOVE";
ca.ca_hostname = hostname;
ca.ca_timestamp = time(NULL);
ca.ca_ch_id = ch_id;
ca.ca_encl_id = -1;
ca.ca_fru_type_id = EVT_ELEM_TYPE_DISK;
ca.ca_fru_id = i;
ca.ca_from_stat = -1;
ca.ca_to_stat = -1;
th_callout(&ca);
}
ch = agent_find_ch_by_cid(ch_id);
if (ch == NULL)
th_fatal("agent_find_ch_by_cid() failed: Cannot find channel %d\n", ch_id);
result = agent_set_drv_remove(ch, fcid_bm, 1);
DBG(D_ESI, "return value = %d\n", result);
if (result)
return(&result);
/*
* Execute post-remove callout for all devices to be removed
*/
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i)) {
ca.ca_name = CFG->ac_postremovalco;
ca.ca_typename = "POST-REMOVE";
ca.ca_hostname = hostname;
ca.ca_timestamp = time(NULL);
ca.ca_ch_id = ch_id;
ca.ca_encl_id = -1;
ca.ca_fru_type_id = EVT_ELEM_TYPE_DISK;
ca.ca_fru_id = i;
ca.ca_from_stat = -1;
ca.ca_to_stat = -1;
th_callout(&ca);
}
return(&result);
}
/*
******************************************************************************
* agent_set_drv_insert_1() - unsigned int AGENT_SET_DRV_INSERT(drive_op_t) = 5;
******************************************************************************
*/
int *agent_set_drv_insert_1(drive_op_t *dop)
{
channel_e_t ch;
u_int ch_id = dop->ch_id;
u_int op = dop->op;
fcid_bitmap_t fcid_bm = (fcid_bitmap_t)dop->fcid_bm.fcid_t_val;
int i;
char hostname[MAXHOSTNAMELEN];
ca_struct_t ca;
static int result=0;
if (__debug & D_ESI) {
printf("DRV_INSERT: CH = %d, OP = %d, FCIDS = ", ch_id, op);
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i))
printf("%d ", i);
printf("\n");
}
ch = agent_find_ch_by_cid(ch_id);
if (ch == NULL)
th_fatal("agent_find_ch_by_cid() failed: Cannot find channel %d\n", ch_id);
result = agent_set_drv_insert(ch, fcid_bm, 1);
DBG(D_ESI, "return value = %d\n", result);
if (result)
return(&result);
if (gethostname(hostname, MAXHOSTNAMELEN))
th_fatal("gethostname() failed: %s\n", strerror(errno));
/*
* Execute post-insert callout for all devices to be removed
*/
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i)) {
ca.ca_name = CFG->ac_postinsertco;
ca.ca_typename = "POST-INSERT";
ca.ca_hostname = hostname;
ca.ca_timestamp = time(NULL);
ca.ca_ch_id = ch_id;
ca.ca_encl_id = -1;
ca.ca_fru_type_id = EVT_ELEM_TYPE_DISK;
ca.ca_fru_id = i;
ca.ca_from_stat = -1;
ca.ca_to_stat = -1;
th_callout(&ca);
}
return(&result);
}
/*
******************************************************************************
* agent_set_drv_led_1() - unsigned int AGENT_SET_DRV_LED(drive_op_t) = 6;
******************************************************************************
*/
int *agent_set_drv_led_1(drive_op_t *dop)
{
channel_e_t ch;
u_int ch_id = dop->ch_id;
u_int op = dop->op;
fcid_bitmap_t fcid_bm = (fcid_bitmap_t)dop->fcid_bm.fcid_t_val;
int i;
static int result=0;
if (__debug & D_ESI) {
printf("DRV_LED: CH = %d, OP = %d, FCIDS = ", ch_id, op);
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i))
printf("%d ", i);
printf("\n");
}
ch = agent_find_ch_by_cid(ch_id);
if (ch == NULL)
th_fatal("agent_find_ch_by_cid() failed: Cannot find channel %d\n", ch_id);
result = agent_set_drv_led(ch, fcid_bm, op);
DBG(D_ESI, "return value = %d\n", result);
return(&result);
}
/*
******************************************************************************
* agent_set_drv_bypass_1() - unsigned int AGENT_SET_DRV_BYPASS(drive_op_t) = 7;
******************************************************************************
*/
int *agent_set_drv_bypass_1(drive_op_t *dop)
{
channel_e_t ch;
u_int ch_id = dop->ch_id;
u_int op = dop->op;
fcid_bitmap_t fcid_bm = (fcid_bitmap_t)dop->fcid_bm.fcid_t_val;
int i;
static int result=0;
if (__debug & D_ESI) {
printf("DRV_BYPASS: CH = %d, OP = %d, FCIDS = ", ch_id, op);
for (i = 0; i < NFCIDBITS; ++i)
if (FCID_ISSET(fcid_bm, i))
printf("%d ", i);
printf("\n");
}
ch = agent_find_ch_by_cid(ch_id);
if (ch == NULL)
th_fatal("agent_find_ch_by_cid() failed: Cannot find channel %d\n", ch_id);
result = agent_set_drv_bypass(ch, fcid_bm, op);
DBG(D_ESI, "return value = %d\n", result);
return(&result);
}
char *frutype2str(uint type)
{
switch(type) {
case EVT_ELEM_TYPE_DISK:
return("DISK");
case EVT_ELEM_TYPE_PS:
return("PS");
case EVT_ELEM_TYPE_FAN:
return("FAN");
case EVT_ELEM_TYPE_UPS:
return("UPS");
case EVT_ELEM_TYPE_LCC:
return("LCC");
default:
return("Unknown");
}
}
char *stat2str(uint stat)
{
switch(stat) {
case EVT_ELEM_STS_OK:
return("OK");
case EVT_ELEM_STS_OFF:
return("OFF");
case EVT_ELEM_STS_FAILED:
return("FAILED");
case EVT_ELEM_STS_NOT_PRESENT:
return("NOT-PRESENT");
case EVT_ELEM_STS_BYPASSED:
return("BYPASSED");
case EVT_ELEM_STS_PEER_FAILED:
return("PEER-FAILED");
default:
return("Unknown");
}
}