/* $Id: apcmastersnmp.c,v 1.8.2.5 2005/04/27 18:58:41 blaschke Exp $ */ /* * Stonith module for APC Masterswitch (SNMP) * Copyright (c) 2001 Andreas Piesk * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #ifdef HAVE_NET_SNMP_NET_SNMP_CONFIG_H # include # include # include # define INIT_AGENT() init_master_agent() #else # include # include # include # ifndef NETSNMP_DS_APPLICATION_ID # define NETSNMP_DS_APPLICATION_ID DS_APPLICATION_ID # endif # ifndef NETSNMP_DS_AGENT_ROLE # define NETSNMP_DS_AGENT_ROLE DS_AGENT_ROLE # endif # define netsnmp_ds_set_boolean ds_set_boolean # define INIT_AGENT() init_master_agent(161, NULL, NULL) #endif #include #define PIL_PLUGINTYPE STONITH_TYPE #define PIL_PLUGINTYPE_S STONITH_TYPE_S #define PIL_PLUGIN apcmastersnmp #define PIL_PLUGIN_S "apcmastersnmp" #define PIL_PLUGINLICENSE LICENSE_LGPL #define PIL_PLUGINLICENSEURL URL_LGPL #include /* * apcmastersnmpclose is called as part of unloading the apcmastersnmp STONITH plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */ static void apcmastersnmpclosepi(PILPlugin*pi) { } /* * apcmastersnmpcloseintf called as part of shutting down the apcmastersnmp STONITH * interface. If there was any global data allocated, or file descriptors * opened, etc. which is associated with the apcmastersnmp implementation, * here's our chance to clean it up. */ static PIL_rc apcmastersnmpcloseintf(PILInterface* pi, void* pd) { return PIL_OK; } void * apcmastersnmp_new(void); void apcmastersnmp_destroy(Stonith *); int apcmastersnmp_set_config_file(Stonith *, const char * cfgname); int apcmastersnmp_set_config_info(Stonith *, const char * info); const char * apcmastersnmp_getinfo(Stonith * s, int InfoType); int apcmastersnmp_status(Stonith * ); int apcmastersnmp_reset_req(Stonith * s, int request, const char * host); char ** apcmastersnmp_hostlist(Stonith *); void apcmastersnmp_free_hostlist(char **); static struct stonith_ops apcmastersnmpOps ={ apcmastersnmp_new, /* Create new STONITH object */ apcmastersnmp_destroy, /* Destroy STONITH object */ apcmastersnmp_set_config_file, /* set configuration from file */ apcmastersnmp_set_config_info, /* Get configuration from file */ apcmastersnmp_getinfo, /* Return STONITH info string */ apcmastersnmp_status, /* Return STONITH device status */ apcmastersnmp_reset_req, /* Request a reset */ apcmastersnmp_hostlist, /* Return list of supported hosts */ apcmastersnmp_free_hostlist /* free above list */ }; PIL_PLUGIN_BOILERPLATE("1.0", Debug, apcmastersnmpclosepi); static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static StonithImports* OurImports; static void* interfprivate; #define APC_MALLOC PluginImports->alloc #define APC_STRDUP PluginImports->mstrdup #define APC_FREE PluginImports->mfree PIL_rc PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports); PIL_rc PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports) { /* Force the compiler to do a little type checking */ (void)(PILPluginInitFun)PIL_PLUGIN_INIT; PluginImports = imports; OurPlugin = us; /* Register ourself as a plugin */ imports->register_plugin(us, &OurPIExports); /* Register our interface implementation */ return imports->register_interface(us, PIL_PLUGINTYPE_S , PIL_PLUGIN_S , &apcmastersnmpOps , apcmastersnmpcloseintf /*close */ , &OurInterface , (void*)&OurImports , &interfprivate); } /* * APCMaster tested with APC Masterswitch 9212 */ /* device ID */ #define DEVICE "APCMasterSNMP-Stonith" /* outlet commands / status codes */ #define OUTLET_ON 1 #define OUTLET_OFF 2 #define OUTLET_REBOOT 3 #define OUTLET_NO_CMD_PEND 2 /* oids */ #define OID_IDENT ".1.3.6.1.4.1.318.1.1.4.1.4.0" #define OID_NUM_OUTLETS ".1.3.6.1.4.1.318.1.1.4.4.1.0" #define OID_OUTLET_NAMES ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.%i" #define OID_OUTLET_STATE ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.%i" #define OID_OUTLET_COMMAND_PENDING ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.%i" #define OID_OUTLET_REBOOT_DURATION ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.%i" /* own defines */ #define MAX_STRING 128 /* structur of stonith object */ struct APCDevice { const char *APCid; /* id of object */ struct snmp_session *sptr; /* != NULL -> session created */ char *hostname; /* masterswitch's hostname or ip address */ int port; /* snmp port */ char *community; /* snmp community (r/w access) */ int num_outlets; /* number of outlets */ }; /* for checking hardware (issue a warning if mismatch) */ static const char* APC_tested_ident[] = {"AP9606","AP7920","AP_other_well_tested"}; /* constant strings */ static const char *APCid = DEVICE; static const char *NOTapcID = "destroyed (APCMasterswitch)"; #ifndef MIN /* some macros */ # define MIN( i, j ) ( i > j ? j : i ) #endif #define ISAPCDEV(i) (((i)!= NULL && (i)->pinfo != NULL) && \ ((struct APCDevice *)(i->pinfo))->APCid == APCid) #define ISCONFIGED(i) (((struct APCDevice *)(i->pinfo))->sptr != NULL ) #define _(text) dgettext(ST_TEXTDOMAIN, text) #ifndef APC_MALLOCT # define APC_MALLOCT(t) ((t *)(APC_MALLOC(sizeof(t)))) #endif /* * stonith prototypes */ /* * own prototypes */ void APC_error(struct snmp_session *sptr, const char *fn, const char *msg); struct snmp_session *APC_open(char *hostname, int port, char *community); int APC_parse_config_info(struct APCDevice *ad, const char *info); void *APC_read(struct snmp_session *sptr, const char *objname, int type); int APC_write(struct snmp_session *sptr, const char *objname, char type, char *value); /* * log snmp error */ void APC_error(struct snmp_session *sptr, const char *fn, const char *msg) { int snmperr = 0; int cliberr = 0; char *errstr; snmp_error(sptr, &cliberr, &snmperr, &errstr); syslog(LOG_ERR, "%s: %s (cliberr: %i / snmperr: %i / error: %s).", fn, msg, cliberr, snmperr, errstr); free(errstr); } /* * creates a snmp session */ struct snmp_session *APC_open(char *hostname, int port, char *community) { static struct snmp_session session; struct snmp_session *sptr; /* create session */ snmp_sess_init(&session); /* fill session */ session.peername = hostname; session.version = SNMP_VERSION_1; session.remote_port = port; session.community = (unsigned char*) community; session.community_len = strlen(community); session.retries = 5; session.timeout = 1000000; /* open session */ sptr = snmp_open(&session); if (sptr == NULL) { APC_error(&session, __FUNCTION__, "cannot open snmp session"); } /* return pointer to opened session */ return (sptr); } /* * parse config */ int APC_parse_config_info(struct APCDevice *ad, const char *info) { static char hostname[MAX_STRING]; static int port; static char community[MAX_STRING]; int *i; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (sscanf(info, "%s %i %s", hostname, &port, community) == 3) { ad->hostname = hostname; ad->port = port; ad->community = community; /* try to resolve the hostname/ip-address */ if (gethostbyname(hostname) != NULL) { /* init snmp library */ init_snmp("apcmastersnmp"); /* now try to get a snmp session */ if ((ad->sptr = APC_open(hostname, port, community)) != NULL) { /* ok, get the number of outlets from the masterswitch */ if ((i = APC_read(ad->sptr, OID_NUM_OUTLETS, ASN_INTEGER)) == NULL) { syslog(LOG_ERR, "%s: cannot read number of outlets.", __FUNCTION__); return (S_ACCESS); } /* store the number of outlets */ ad->num_outlets = *i; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: number of outlets: %i.", __FUNCTION__, ad->num_outlets ); #endif /* everything went well */ return (S_OK); }else{ syslog(LOG_ERR, "%s: cannot create snmp session.", __FUNCTION__); } }else{ syslog(LOG_ERR, "%s: cannot resolve hostname '%s', h_errno %d.", __FUNCTION__, hostname, h_errno); } }else{ syslog(LOG_ERR, "%s: cannot parse config info '%s'.", __FUNCTION__, info); } /* no valid config */ return (S_BADCONFIG); } /* * read value of given oid and return it as string */ void *APC_read(struct snmp_session *sptr, const char *objname, int type) { oid name[MAX_OID_LEN]; size_t namelen = MAX_OID_LEN; struct variable_list *vars; struct snmp_pdu *pdu; struct snmp_pdu *resp; static char response_str[MAX_STRING]; static int response_int; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: requested objname '%s'.", __FUNCTION__, objname ); #endif /* convert objname into oid; return NULL if invalid */ if (!read_objid(objname, name, &namelen)) { syslog(LOG_ERR, "%s: cannot convert %s to oid.", __FUNCTION__, objname); return (NULL); } /* create pdu */ if ((pdu = snmp_pdu_create(SNMP_MSG_GET)) != NULL) { /* get-request have no values */ snmp_add_null_var(pdu, name, namelen); /* send pdu and get response; return NULL if error */ if (snmp_synch_response(sptr, pdu, &resp) == SNMPERR_SUCCESS) { /* request succeed, got valid response ? */ if (resp->errstat == SNMP_ERR_NOERROR) { /* go through the returned vars */ for (vars = resp->variables; vars; vars = vars->next_variable) { /* return response as string */ if ((vars->type == type) && (type == ASN_OCTET_STR)) { memset(response_str, 0, MAX_STRING); strncpy(response_str, (char*) vars->val.string, MIN(vars->val_len, MAX_STRING)); snmp_free_pdu(resp); return ((void *) response_str); } /* return response as integer */ if ((vars->type == type) && (type == ASN_INTEGER)) { response_int = *vars->val.integer; snmp_free_pdu(resp); return ((void *) &response_int); } } }else{ syslog(LOG_ERR, "%s: error in response packet, reason %ld [%s].", __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat)); } }else{ APC_error(sptr, __FUNCTION__, "error sending/receiving pdu"); } /* free repsonse pdu (necessary?) */ snmp_free_pdu(resp); }else{ APC_error(sptr, __FUNCTION__, "cannot create pdu"); } /* error: return nothing */ return (NULL); } /* * write value of given oid */ int APC_write(struct snmp_session *sptr, const char *objname, char type, char *value) { oid name[MAX_OID_LEN]; size_t namelen = MAX_OID_LEN; struct snmp_pdu *pdu; struct snmp_pdu *resp; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: requested objname '%s'.", __FUNCTION__, objname ); #endif /* convert objname into oid; return NULL if invalid */ if (!read_objid(objname, name, &namelen)) { syslog(LOG_ERR, "%s: cannot convert %s to oid.", __FUNCTION__, objname); return (FALSE); } /* create pdu */ if ((pdu = snmp_pdu_create(SNMP_MSG_SET)) != NULL) { /* add to be written value to pdu */ snmp_add_var(pdu, name, namelen, type, value); /* send pdu and get response; return NULL if error */ if (snmp_synch_response(sptr, pdu, &resp) == STAT_SUCCESS) { /* go through the returned vars */ if (resp->errstat == SNMP_ERR_NOERROR) { /* request successful done */ snmp_free_pdu(resp); return (TRUE); } else { syslog(LOG_ERR, "%s: error in response packet, reason %ld [%s].", __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat)); } }else{ APC_error(sptr, __FUNCTION__, "error sending/receiving pdu"); } /* free pdu (again: necessary?) */ snmp_free_pdu(resp); }else{ APC_error(sptr, __FUNCTION__, "cannot create pdu"); } /* error */ return (FALSE); } /* * return the status for this device */ int apcmastersnmp_status(Stonith * s) { struct APCDevice *ad; char *ident; int i; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } if (!ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__); return (S_OOPS); } ad = (struct APCDevice *) s->pinfo; if ((ident = APC_read(ad->sptr, OID_IDENT, ASN_OCTET_STR)) == NULL) { syslog(LOG_ERR, "%s: cannot read ident.", __FUNCTION__); return (S_ACCESS); } /* issue a warning if ident mismatches */ for(i=DIMOF(APC_tested_ident) -1; i >=0 ; i--) if (strcmp(ident, APC_tested_ident[i]) == 0) break; if (i<0) { syslog(LOG_WARNING, "%s: module not tested with this hardware '%s'.", __FUNCTION__, ident); } /* status ok */ return (S_OK); } /* * return the list of hosts configured for this device */ char ** apcmastersnmp_hostlist(Stonith * s) { char **hl; struct APCDevice *ad; int j, h, num_outlets; char *outlet_name; char objname[MAX_STRING]; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (NULL); } if (!ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__); return (NULL); } ad = (struct APCDevice *) s->pinfo; /* allocate memory for array of up to NUM_OUTLETS strings */ if ((hl = (char **) APC_MALLOC(ad->num_outlets * sizeof(char *))) == NULL) { syslog(LOG_ERR, "%s: out of memory.", __FUNCTION__); return (NULL); } /* clear hostlist array */ memset(hl, 0, (ad->num_outlets + 1) * sizeof(char *)); num_outlets = 0; /* read NUM_OUTLETS values and put them into hostlist array */ for (j = 0; j < ad->num_outlets; ++j) { /* prepare objname */ snprintf(objname, MAX_STRING, OID_OUTLET_NAMES, j + 1); /* read outlet name */ if ((outlet_name = APC_read(ad->sptr, objname, ASN_OCTET_STR)) == NULL) { syslog(LOG_ERR, "%s: cannot read name for outlet %d.", __FUNCTION__, j+1); apcmastersnmp_free_hostlist(hl); hl = NULL; return (hl); } /* Check whether the host is already listed */ for (h = 0; h < num_outlets; ++h) { if (strcmp(hl[h],outlet_name) == 0) break; } if (h >= num_outlets) { /* put outletname in hostlist */ #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: added %s to hostlist.", __FUNCTION__, outlet_name); #endif if ((hl[num_outlets] = APC_STRDUP(outlet_name)) == NULL) { syslog(LOG_ERR, "%s: out of memory.", __FUNCTION__); apcmastersnmp_free_hostlist(hl); hl = NULL; return (hl); } num_outlets++; } } #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: %d unique hosts connected to %d outlets.", __FUNCTION__, num_outlets, j); #endif /* return list */ return (hl); } /* * free the hostlist */ void apcmastersnmp_free_hostlist(char **hlist) { char **hl = hlist; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif /* empty list */ if (hl == NULL) return; /* walk through the list and release the strings */ while (*hl) { APC_FREE(*hl); *hl = NULL; ++hl; } /* release the list itself */ APC_FREE(hlist); hlist = NULL; } /* * reset the host */ int apcmastersnmp_reset_req(Stonith * s, int request, const char *host) { struct APCDevice *ad; char objname[MAX_STRING]; char value[MAX_STRING]; char *outlet_name; int i, h, num_outlets, outlet, reboot_duration, *state, bad_outlets; int outlets[8]; /* Assume that one node is connected to a maximum of 8 outlets */ #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } if (!ISCONFIGED(s)) { syslog(LOG_ERR, "%s: device is UNCONFIGURED!", __FUNCTION__); return (S_OOPS); } ad = (struct APCDevice *) s->pinfo; num_outlets = 0; reboot_duration = 0; bad_outlets = 0; /* read max. as->num_outlets values */ for (outlet = 1; outlet <= ad->num_outlets; outlet++) { /* prepare objname */ snprintf(objname, MAX_STRING, OID_OUTLET_NAMES, outlet); /* read outlet name */ if ((outlet_name = APC_read(ad->sptr, objname, ASN_OCTET_STR)) == NULL) { syslog(LOG_ERR, "%s: cannot read name for outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } /* found one */ g_strdown(outlet_name); if (strcmp(outlet_name, host) == 0) { #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: found %s at outlet %i.", __FUNCTION__, host, outlet); #endif /* Check that the outlet is not administratively down */ /* prepare objname */ snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet); /* get outlet's state */ if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) { syslog(LOG_ERR, "%s: cannot read state for outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } if (*state == OUTLET_OFF) { #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: outlet %d is off.", __FUNCTION__, outlet); #endif continue; } /* prepare oid */ snprintf(objname, MAX_STRING, OID_OUTLET_REBOOT_DURATION, outlet); /* read reboot_duration of the port */ if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) { syslog(LOG_ERR, "%s: cannot read reboot duration for outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } if (num_outlets == 0) { /* save the inital value of the first port */ reboot_duration = *state; } else if (reboot_duration != *state) { syslog(LOG_WARNING, "%s: outlet %d has a different reboot " "duration!", __FUNCTION__, outlet); if (reboot_duration < *state) reboot_duration = *state; } /* Ok, add it to the list of outlets to control */ outlets[num_outlets]=outlet; num_outlets++; } } #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: outlet: %i.", __FUNCTION__, outlet); #endif /* host not found in outlet names */ if (num_outlets < 1) { syslog(LOG_ERR, "%s: no active outlet for '%s'.", __FUNCTION__, host); return (S_BADHOST); } /* Turn them all off */ for (outlet=outlets[0], i=0 ; i < num_outlets; i++, outlet = outlets[i]) { /* prepare objname */ snprintf(objname, MAX_STRING, OID_OUTLET_COMMAND_PENDING, outlet); /* are there pending commands ? */ if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) { syslog(LOG_ERR, "%s: cannot read pending commands for " "outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } if (*state != OUTLET_NO_CMD_PEND) { #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: command pending.", __FUNCTION__); #endif return (S_RESETFAIL); } /* prepare objnames */ snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet); snprintf(value, MAX_STRING, "%i", OUTLET_REBOOT); /* send reboot cmd */ if (!APC_write(ad->sptr, objname, 'i', value)) { syslog(LOG_ERR, "%s: cannot send reboot command for outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } } /* wait max. 2*reboot_duration for all outlets to go back on */ for (i = 0; i < reboot_duration << 1; i++) { sleep(1); bad_outlets = 0; for (outlet=outlets[0], h=0 ; h < num_outlets; h++, outlet = outlets[h]) { /* prepare objname of the first outlet */ snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet); /* get outlet's state */ if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) { syslog(LOG_ERR, "%s: cannot read state for outlet %d.", __FUNCTION__, outlet); return (S_ACCESS); } if (*state != OUTLET_ON) bad_outlets++; } if (bad_outlets == 0) return (S_OK); } if (bad_outlets == num_outlets) { /* reset failed */ syslog(LOG_ERR, "%s: resetting host '%s' failed.", __FUNCTION__, host); return (S_RESETFAIL); } else { /* Not all outlets back on, but at least one; implies the node was */ /* rebooted correctly */ syslog(LOG_WARNING,"%s: Not all outlets came back online!", __FUNCTION__); return (S_OK); } } /* * parse the information in the given configuration file, * and stash it away... */ int apcmastersnmp_set_config_file(Stonith * s, const char *configname) { FILE *cfgfile; char confline[MAX_STRING]; struct APCDevice *ad; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called, file '%s'.", __FUNCTION__, configname); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } ad = (struct APCDevice *) s->pinfo; if ((cfgfile = fopen(configname, "r")) == NULL) { syslog(LOG_ERR, "cannot open %s.", configname); return (S_BADCONFIG); } while (fgets(confline, sizeof(confline), cfgfile) != NULL) { if (*confline == '#' || *confline == '\n' || *confline == EOS) continue; return (APC_parse_config_info(ad, confline)); } return (S_BADCONFIG); } /* * Parse the config information in the given string, and stash it away... */ int apcmastersnmp_set_config_info(Stonith * s, const char *info) { struct APCDevice *ad; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called, info '%s'.", __FUNCTION__, info); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (S_INVAL); } ad = (struct APCDevice *) s->pinfo; return (APC_parse_config_info(ad, info)); } /* * get info about the stonith device */ const char * apcmastersnmp_getinfo(Stonith * s, int reqtype) { struct APCDevice *ad; const char *ret = NULL; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return (NULL); } ad = (struct APCDevice *) s->pinfo; switch (reqtype) { case ST_DEVICEID: ret = ad->APCid; break; case ST_CONF_INFO_SYNTAX: ret = _("hostname/ip-address port community\n" "The hostname/IP-address, SNMP port and community string are white-space delimited."); break; case ST_CONF_FILE_SYNTAX: ret = _("hostname/ip-address port community\n" "The hostname/IP-address, SNMP port and community string are white-space delimited.\n" "All items must be on one line.\n" "Blank lines and lines beginning with # are ignored."); break; case ST_DEVICEDESCR: ret = _("APC MasterSwitch (via SNMP)\n" "The APC MasterSwitch can accept multiple simultaneous SNMP clients"); break; case ST_DEVICEURL: ret = "http://www.apc.com/"; break; } return ret; } /* * APC Stonith destructor... */ void apcmastersnmp_destroy(Stonith * s) { struct APCDevice *ad; #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif if (!ISAPCDEV(s)) { syslog(LOG_ERR, "%s: invalid argument.", __FUNCTION__); return; } ad = (struct APCDevice *) s->pinfo; ad->APCid = NOTapcID; /* release snmp session */ if (ad->sptr != NULL) { snmp_close(ad->sptr); ad->sptr = NULL; } /* reset defaults */ ad->hostname = NULL; ad->community = NULL; ad->num_outlets = 0; APC_FREE(ad); /* Our caller will release the STONITH object itself */ } /* * Create a new APC Stonith device. Too bad this function can't be * static */ void * apcmastersnmp_new(void) { struct APCDevice *ad = APC_MALLOCT(struct APCDevice); #ifdef APC_DEBUG syslog(LOG_DEBUG, "%s: called.", __FUNCTION__); #endif /* no memory for stonith-object */ if (ad == NULL) { syslog(LOG_ERR, "%s: out of memory.", __FUNCTION__); return (NULL); } /* clear stonith-object */ memset(ad, 0, sizeof(*ad)); /* set defaults */ ad->APCid = APCid; ad->sptr = NULL; ad->hostname = NULL; ad->community = NULL; ad->num_outlets = 0; /* return the object */ return ((void *) ad); }