📄 apcmastersnmp.c
字号:
/* $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 voidapcmastersnmpclosepi(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_rcapcmastersnmpcloseintf(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->mfreePIL_rcPIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);PIL_rcPIL_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 */intAPC_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 */intAPC_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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -