/* $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 <a.piesk@gmx.net>
*
* 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 <portability.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <errno.h>
#include <libintl.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <glib.h>
#ifdef HAVE_NET_SNMP_NET_SNMP_CONFIG_H
# include <net-snmp/net-snmp-config.h>
# include <net-snmp/net-snmp-includes.h>
# include <net-snmp/agent/net-snmp-agent-includes.h>
# define INIT_AGENT() init_master_agent()
#else
# include <ucd-snmp/ucd-snmp-config.h>
# include <ucd-snmp/ucd-snmp-includes.h>
# include <ucd-snmp/ucd-snmp-agent-includes.h>
# 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 <stonith/stonith.h>
#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 <pils/plugin.h>
/*
* 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);
}
syntax highlighted by Code2HTML, v. 0.9.1