summaryrefslogtreecommitdiffstats
path: root/lib/plugins/stonith/wti_nps.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/plugins/stonith/wti_nps.c')
-rw-r--r--lib/plugins/stonith/wti_nps.c813
1 files changed, 813 insertions, 0 deletions
diff --git a/lib/plugins/stonith/wti_nps.c b/lib/plugins/stonith/wti_nps.c
new file mode 100644
index 0000000..f0b81f7
--- /dev/null
+++ b/lib/plugins/stonith/wti_nps.c
@@ -0,0 +1,813 @@
+/*
+ *
+ * Copyright 2001 Mission Critical Linux, Inc.
+ *
+ * All Rights Reserved.
+ */
+/*
+ * Stonith module for WTI Network Power Switch Devices (NPS-xxx)
+ * Also supports the WTI Telnet Power Switch Devices (TPS-xxx)
+ *
+ * Copyright 2001 Mission Critical Linux, Inc.
+ * author: mike ledoux <mwl@mclinux.com>
+ * author: Todd Wheeling <wheeling@mclinux.com>
+ * Mangled by Zhaokai <zhaokai@cn.ibm.com>, IBM, 2005
+ * Further hurt by Lon <lhh@redhat.com>, Red Hat, 2005
+ *
+ * Supported WTI devices:
+ * NPS-115
+ * NPS-230
+ * IPS-15
+ * IPS-800
+ * IPS-800-CE
+ * NBB-1600
+ * NBB-1600-CE
+ * TPS-2
+ *
+ * Based strongly on original code from baytech.c by Alan Robertson.
+ *
+ * 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
+ *
+ */
+
+/* Observations/Notes
+ *
+ * 1. The WTI Network Power Switch, unlike the BayTech network power switch,
+ * accpets only one (telnet) connection/session at a time. When one
+ * session is active, any subsequent attempt to connect to the NPS will
+ * result in a connection refused/closed failure. In a cluster environment
+ * or other environment utilizing polling/monitoring of the NPS
+ * (from multiple nodes), this can clearly cause problems. Obviously the
+ * more nodes and the shorter the polling interval, the more frequently such
+ * errors/collisions may occur.
+ *
+ * 2. We observed that on busy networks where there may be high occurances
+ * of broadcasts, the NPS became unresponsive. In some
+ * configurations this necessitated placing the power switch onto a
+ * private subnet.
+ */
+
+#include <lha_internal.h>
+#define DEVICE "WTI Network Power Switch"
+
+#define DOESNT_USE_STONITHKILLCOMM 1
+
+#include "stonith_plugin_common.h"
+
+#define PIL_PLUGIN wti_nps
+#define PIL_PLUGIN_S "wti_nps"
+#define PIL_PLUGINLICENSE LICENSE_LGPL
+#define PIL_PLUGINLICENSEURL URL_LGPL
+#define MAX_WTIPLUGINID 256
+
+#include <pils/plugin.h>
+
+#include "stonith_signal.h"
+
+static StonithPlugin * wti_nps_new(const char *);
+static void wti_nps_destroy(StonithPlugin *);
+static const char * const * wti_nps_get_confignames(StonithPlugin *);
+static int wti_nps_set_config(StonithPlugin * , StonithNVpair * );
+static const char * wti_nps_get_info(StonithPlugin * s, int InfoType);
+static int wti_nps_status(StonithPlugin * );
+static int wti_nps_reset_req(StonithPlugin * s, int request, const char * host);
+static char ** wti_nps_hostlist(StonithPlugin *);
+
+static struct stonith_ops wti_npsOps ={
+ wti_nps_new, /* Create new STONITH object */
+ wti_nps_destroy, /* Destroy STONITH object */
+ wti_nps_get_info, /* Return STONITH info string */
+ wti_nps_get_confignames,/* Return configration parameters */
+ wti_nps_set_config, /* set configration */
+ wti_nps_status, /* Return STONITH device status */
+ wti_nps_reset_req, /* Request a reset */
+ wti_nps_hostlist, /* Return list of supported hosts */
+};
+
+PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
+static const PILPluginImports* PluginImports;
+static PILPlugin* OurPlugin;
+static PILInterface* OurInterface;
+static StonithImports* OurImports;
+static void* interfprivate;
+
+#include "stonith_expect_helpers.h"
+
+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
+ , &wti_npsOps
+ , NULL /*close */
+ , &OurInterface
+ , (void*)&OurImports
+ , &interfprivate);
+}
+
+/*
+ * I have a NPS-110. This code has been tested with this switch.
+ * (Tested with NPS-230 and TPS-2 by lmb)
+ */
+
+struct pluginDevice {
+ StonithPlugin sp;
+ const char * pluginid;
+ const char * idinfo;
+ pid_t pid;
+ int rdfd;
+ int wrfd;
+ char * device;
+ char * passwd;
+};
+
+static const char * pluginid = "WTINPS-Stonith";
+static const char * NOTnpsid = "WTINPS device has been destroyed";
+
+#include "stonith_config_xml.h"
+
+static const char *wti_npsXML =
+ XML_PARAMETERS_BEGIN
+ XML_IPADDR_PARM
+ XML_PASSWD_PARM
+ XML_PARAMETERS_END;
+
+
+/*
+ * Different expect strings that we get from the WTI
+ * Network Power Switch
+ */
+
+#define WTINPSSTR " Power Switch"
+#define WTINBBSTR "Boot Bar"
+
+static struct Etoken password[] = { {"Password:", 0, 0}, {NULL,0,0}};
+static struct Etoken Prompt[] = { {"PS>", 0, 0}
+ , {"IPS>", 0, 0}
+ , {"BB>", 0, 0}
+ , {NULL,0,0}};
+static struct Etoken LoginOK[] = { {WTINPSSTR, 0, 0}
+ , {WTINBBSTR, 0, 0}
+ , {"Invalid password", 1, 0}
+ , {NULL,0,0} };
+static struct Etoken Separator[] = { {"-----+", 0, 0} ,{NULL,0,0}};
+
+/* We may get a notice about rebooting, or a request for confirmation */
+static struct Etoken Processing[] = { {"rocessing - please wait", 0, 0}
+ , {"(Y/N):", 1, 0}
+ , {NULL,0,0}};
+
+static int NPS_connect_device(struct pluginDevice * nps);
+static int NPSLogin(struct pluginDevice * nps);
+static int NPSNametoOutlet(struct pluginDevice*, const char * name, char **outlets);
+static int NPSReset(struct pluginDevice*, char * outlets, const char * rebootid);
+static int NPSLogout(struct pluginDevice * nps);
+
+#if defined(ST_POWERON) && defined(ST_POWEROFF)
+static int NPS_onoff(struct pluginDevice*, const char * outlets, const char * unitid
+, int request);
+#endif
+
+/* Attempt to login up to 20 times... */
+static int
+NPSRobustLogin(struct pluginDevice * nps)
+{
+ int rc = S_OOPS;
+ int j = 0;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ for ( ; ; ) {
+ if (NPS_connect_device(nps) == S_OK) {
+ rc = NPSLogin(nps);
+ if (rc == S_OK) {
+ break;
+ }
+ }
+ if ((++j) == 20) {
+ break;
+ }
+ else {
+ sleep(1);
+ }
+ }
+
+ return rc;
+}
+
+/* Login to the WTI Network Power Switch (NPS) */
+static int
+NPSLogin(struct pluginDevice * nps)
+{
+ char IDinfo[128];
+ char * idptr = IDinfo;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ /* Look for the unit type info */
+ if (EXPECT_TOK(nps->rdfd, password, 2, IDinfo
+ , sizeof(IDinfo), Debug) < 0) {
+ LOG(PIL_CRIT, "No initial response from %s.", nps->idinfo);
+ return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
+ }
+ idptr += strspn(idptr, WHITESPACE);
+ /*
+ * We should be looking at something like this:
+ * Enter Password:
+ */
+
+ SEND(nps->wrfd, nps->passwd);
+ SEND(nps->wrfd, "\r");
+ /* Expect "Network Power Switch vX.YY" */
+
+ switch (StonithLookFor(nps->rdfd, LoginOK, 5)) {
+
+ case 0: /* Good! */
+ LOG(PIL_INFO, "Successful login to %s.", nps->idinfo);
+ break;
+
+ case 1: /* Uh-oh - bad password */
+ LOG(PIL_CRIT, "Invalid password for %s.", nps->idinfo);
+ return(S_ACCESS);
+
+ default:
+ return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
+ }
+ return(S_OK);
+}
+
+/* Log out of the WTI NPS */
+
+static int
+NPSLogout(struct pluginDevice* nps)
+{
+ int rc;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ /* Send "/h" help command and expect back prompt */
+ /*
+ SEND(nps->wrfd, "/h\r");
+ */
+ /* Expect "PS>" */
+ rc = StonithLookFor(nps->rdfd, Prompt, 5);
+
+ /* "/x" is Logout, "/x,y" auto-confirms */
+ SEND(nps->wrfd, "/x,y\r");
+
+ close(nps->wrfd);
+ close(nps->rdfd);
+ nps->wrfd = nps->rdfd = -1;
+
+ return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));
+}
+
+/* Reset (power-cycle) the given outlets */
+static int
+NPSReset(struct pluginDevice* nps, char * outlets, const char * rebootid)
+{
+ char unum[32];
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ /* Send "/h" help command and expect back prompt */
+ SEND(nps->wrfd, "/h\r");
+ /* Expect "PS>" */
+ EXPECT(nps->rdfd, Prompt, 5);
+
+ /* Send REBOOT command for given outlets */
+ snprintf(unum, sizeof(unum), "/BOOT %s,y\r", outlets);
+ SEND(nps->wrfd, unum);
+
+ /* Expect "Processing "... or "(Y/N)" (if confirmation turned on) */
+
+ retry:
+ switch (StonithLookFor(nps->rdfd, Processing, 5)) {
+ case 0: /* Got "Processing" Do nothing */
+ break;
+
+ case 1: /* Got that annoying command confirmation :-( */
+ SEND(nps->wrfd, "Y\r");
+ goto retry;
+
+ default:
+ return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
+ }
+ LOG(PIL_INFO, "Host is being rebooted: %s", rebootid);
+
+ /* Expect "PS>" */
+ if (StonithLookFor(nps->rdfd, Prompt, 60) < 0) {
+ return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
+ }
+
+ /* All Right! Power is back on. Life is Good! */
+
+ LOG(PIL_INFO, "Power restored to host: %s", rebootid);
+ SEND(nps->wrfd, "/h\r");
+ return(S_OK);
+}
+
+#if defined(ST_POWERON) && defined(ST_POWEROFF)
+static int
+NPS_onoff(struct pluginDevice* nps, const char * outlets, const char * unitid, int req)
+{
+ char unum[32];
+
+ const char * onoff = (req == ST_POWERON ? "/On" : "/Off");
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ /* Send "/h" help command and expect prompt back */
+ SEND(nps->wrfd, "/h\r");
+ /* Expect "PS>" */
+ EXPECT(nps->rdfd, Prompt, 5);
+
+ /* Send ON/OFF command for given outlet */
+ snprintf(unum, sizeof(unum), "%s %s,y\r", onoff, outlets);
+ SEND(nps->wrfd, unum);
+
+ /* Expect "Processing"... or "(Y/N)" (if confirmation turned on) */
+
+ if (StonithLookFor(nps->rdfd, Processing, 5) == 1) {
+ /* They've turned on that annoying command confirmation :-( */
+ SEND(nps->wrfd, "Y\r");
+ }
+ EXPECT(nps->rdfd, Prompt, 60);
+
+ /* All Right! Command done. Life is Good! */
+ LOG(PIL_INFO, "Power to NPS outlet(s) %s turned %s", outlets, onoff);
+
+ SEND(nps->wrfd, "/h\r");
+ return(S_OK);
+}
+#endif /* defined(ST_POWERON) && defined(ST_POWEROFF) */
+
+/*
+ * Map the given host name into an (AC) Outlet number on the power strip
+ */
+
+static int
+NPSNametoOutlet(struct pluginDevice* nps, const char * name, char **outlets)
+{
+ char NameMapping[128];
+ int sockno;
+ char sockname[32];
+ char buf[32];
+ int left = 17;
+ int ret = -1;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ if ((*outlets = (char *)MALLOC(left*sizeof(char))) == NULL) {
+ LOG(PIL_CRIT, "out of memory");
+ return(-1);
+ }
+
+ strncpy(*outlets, "", left);
+ left = left - 1; /* ensure terminating '\0' */
+ /* Expect "PS>" */
+ EXPECT(nps->rdfd, Prompt, 5);
+
+ /* The status command output contains mapping of hosts to outlets */
+ SEND(nps->wrfd, "/s\r");
+
+ /* Expect: "-----+" so we can skip over it... */
+ EXPECT(nps->rdfd, Separator, 5);
+
+ do {
+ NameMapping[0] = EOS;
+ SNARF(nps->rdfd, NameMapping, 5);
+
+ if (sscanf(NameMapping
+ , "%d | %16c",&sockno, sockname) == 2) {
+
+ char * last = sockname+16;
+ *last = EOS;
+ --last;
+ /* Strip off trailing blanks */
+ for(; last > sockname; --last) {
+ if (*last == ' ') {
+ *last = EOS;
+ }else{
+ break;
+ }
+ }
+ if (strncasecmp(name, sockname, 16) == 0) {
+ ret = sockno;
+ snprintf(buf, sizeof(buf), "%d ", sockno);
+ strncat(*outlets, buf, left);
+ left = left - strlen(buf);
+ }
+ }
+ } while (strlen(NameMapping) > 2 && left > 0);
+
+ return(ret);
+}
+
+static int
+wti_nps_status(StonithPlugin *s)
+{
+ struct pluginDevice* nps;
+ int rc;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ ERRIFNOTCONFIGED(s,S_OOPS);
+
+ nps = (struct pluginDevice*) s;
+
+ if ((rc = NPSRobustLogin(nps) != S_OK)) {
+ LOG(PIL_CRIT, "Cannot log into %s.", nps->idinfo);
+ return(rc);
+ }
+
+ /* Send "/h" help command and expect back prompt */
+ SEND(nps->wrfd, "/h\r");
+ /* Expect "PS>" */
+ EXPECT(nps->rdfd, Prompt, 5);
+
+ return(NPSLogout(nps));
+}
+
+/*
+ * Return the list of hosts (outlet names) for the devices on this NPS unit
+ */
+
+static char **
+wti_nps_hostlist(StonithPlugin *s)
+{
+ char NameMapping[128];
+ char* NameList[64];
+ unsigned int numnames = 0;
+ char ** ret = NULL;
+ struct pluginDevice* nps;
+ unsigned int i;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ ERRIFNOTCONFIGED(s,NULL);
+
+ nps = (struct pluginDevice*) s;
+ if (NPSRobustLogin(nps) != S_OK) {
+ LOG(PIL_CRIT, "Cannot log into %s.", nps->idinfo);
+ return(NULL);
+ }
+
+ /* Expect "PS>" */
+ NULLEXPECT(nps->rdfd, Prompt, 5);
+
+ /* The status command output contains mapping of hosts to outlets */
+ SEND(nps->wrfd, "/s\r");
+
+ /* Expect: "-----" so we can skip over it... */
+ NULLEXPECT(nps->rdfd, Separator, 5);
+ NULLEXPECT(nps->rdfd, CRNL, 5);
+
+ /* Looks Good! Parse the status output */
+
+ do {
+ int sockno;
+ char sockname[64];
+ NameMapping[0] = EOS;
+ NULLSNARF(nps->rdfd, NameMapping, 5);
+ if (sscanf(NameMapping
+ , "%d | %16c",&sockno, sockname) == 2) {
+
+ char * last = sockname+16;
+ char * nm;
+ *last = EOS;
+ --last;
+
+ /* Strip off trailing blanks */
+ for(; last > sockname; --last) {
+ if (*last == ' ') {
+ *last = EOS;
+ }else{
+ break;
+ }
+ }
+ if (numnames >= DIMOF(NameList)-1) {
+ break;
+ }
+ if (!strcmp(sockname,"(undefined)") ||
+ !strcmp(sockname,"---")) {
+ /* lhh - skip undefined */
+ continue;
+ }
+ if ((nm = STRDUP(sockname)) == NULL) {
+ goto out_of_memory;
+ }
+ strdown(nm);
+ NameList[numnames] = nm;
+ ++numnames;
+ NameList[numnames] = NULL;
+ }
+ } while (strlen(NameMapping) > 2);
+
+ if (numnames >= 1) {
+ ret = (char **)MALLOC((numnames+1)*sizeof(char*));
+ if (ret == NULL) {
+ goto out_of_memory;
+ }else{
+ memset(ret, 0, (numnames+1)*sizeof(char*));
+ memcpy(ret, NameList, (numnames+1)*sizeof(char*));
+ }
+ }
+ (void)NPSLogout(nps);
+
+ return(ret);
+
+out_of_memory:
+ LOG(PIL_CRIT, "out of memory");
+ for (i=0; i<numnames; i++) {
+ FREE(NameList[i]);
+ }
+
+ return (NULL);
+}
+
+/*
+ * Connect to the given NPS device. We should add serial support here
+ * eventually...
+ */
+static int
+NPS_connect_device(struct pluginDevice * nps)
+{
+ int fd = OurImports->OpenStreamSocket(nps->device
+ , TELNET_PORT, TELNET_SERVICE);
+
+ if (fd < 0) {
+ return(S_OOPS);
+ }
+ nps->rdfd = nps->wrfd = fd;
+ return(S_OK);
+}
+
+/*
+ * Reset the given host on this Stonith device.
+ */
+static int
+wti_nps_reset_req(StonithPlugin * s, int request, const char * host)
+{
+ int rc = 0;
+ int lorc = 0;
+ struct pluginDevice* nps;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
+ }
+
+ ERRIFNOTCONFIGED(s,S_OOPS);
+
+ nps = (struct pluginDevice*) s;
+
+ if ((rc = NPSRobustLogin(nps)) != S_OK) {
+ LOG(PIL_CRIT, "Cannot log into %s.", nps->idinfo);
+ }else{
+ char *outlets;
+ int noutlet;
+
+ outlets = NULL;
+ noutlet = NPSNametoOutlet(nps, host, &outlets);
+
+ if (noutlet < 1) {
+ LOG(PIL_WARN, "%s doesn't control host [%s]"
+ , nps->device, host);
+ if (outlets != NULL) {
+ FREE(outlets);
+ outlets = NULL;
+ }
+ return(S_BADHOST);
+ }
+ switch(request) {
+
+#if defined(ST_POWERON) && defined(ST_POWEROFF)
+ case ST_POWERON:
+ case ST_POWEROFF:
+ rc = NPS_onoff(nps, outlets, host, request);
+ if (outlets != NULL) {
+ FREE(outlets);
+ outlets = NULL;
+ }
+ break;
+#endif
+ case ST_GENERIC_RESET:
+ rc = NPSReset(nps, outlets, host);
+ if (outlets != NULL) {
+ FREE(outlets);
+ outlets = NULL;
+ }
+ break;
+ default:
+ rc = S_INVAL;
+ if (outlets != NULL) {
+ FREE(outlets);
+ outlets = NULL;
+ }
+ break;
+ }
+ }
+
+ lorc = NPSLogout(nps);
+ return(rc != S_OK ? rc : lorc);
+}
+
+/*
+ * Parse the information in the given string,
+ * and stash it away...
+ */
+static int
+wti_nps_set_config(StonithPlugin * s, StonithNVpair *list)
+{
+ struct pluginDevice* nps;
+ StonithNamesToGet namestocopy [] =
+ { {ST_IPADDR, NULL}
+ , {ST_PASSWD, NULL}
+ , {NULL, NULL}
+ };
+ int rc;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called.\n", __FUNCTION__);
+ }
+
+ ERRIFWRONGDEV(s,S_OOPS);
+
+ nps = (struct pluginDevice*) s;
+
+ if ((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
+ return rc;
+ }
+ nps->device = namestocopy[0].s_value;
+ nps->passwd = namestocopy[1].s_value;
+ return S_OK;
+}
+
+
+/*
+ * Return the Stonith plugin configuration parameter
+ *
+ */
+static const char * const *
+wti_nps_get_confignames(StonithPlugin * p)
+{
+ static const char * names[] = { ST_IPADDR , ST_PASSWD , NULL};
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);
+ }
+ return names;
+}
+
+/*
+ * Get info about the stonith device
+ *
+ */
+static const char *
+wti_nps_get_info(StonithPlugin * s, int reqtype)
+{
+ struct pluginDevice* nps;
+ const char * ret;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);
+ }
+
+ ERRIFWRONGDEV(s,NULL);
+
+ /*
+ * We look in the ST_TEXTDOMAIN catalog for our messages
+ */
+ nps = (struct pluginDevice *)s;
+
+ switch (reqtype) {
+
+ case ST_DEVICEID:
+ ret = nps->idinfo;
+ break;
+ case ST_DEVICENAME:
+ ret = nps->device;
+ break;
+ case ST_DEVICEDESCR:
+ ret = "Western Telematic (WTI) Network Power Switch Devices (NPS-xxx)\n"
+ "Also supports the WTI Telnet Power Switch Devices (TPS-xxx)\n"
+ "NOTE: The WTI Network Power Switch, accepts only "
+ "one (telnet) connection/session at a time.";
+ break;
+ case ST_DEVICEURL:
+ ret = "http://www.wti.com/";
+ break;
+ case ST_CONF_XML: /* XML metadata */
+ ret = wti_npsXML;
+ break;
+ default:
+ ret = NULL;
+ break;
+ }
+ return ret;
+}
+
+/*
+ * WTI NPS Stonith destructor...
+ */
+static void
+wti_nps_destroy(StonithPlugin *s)
+{
+ struct pluginDevice* nps;
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);
+ }
+
+ VOIDERRIFWRONGDEV(s);
+
+ nps = (struct pluginDevice *)s;
+
+ nps->pluginid = NOTnpsid;
+ if (nps->rdfd >= 0) {
+ close(nps->rdfd);
+ nps->rdfd = -1;
+ }
+ if (nps->wrfd >= 0) {
+ close(nps->wrfd);
+ nps->wrfd = -1;
+ }
+ if (nps->device != NULL) {
+ FREE(nps->device);
+ nps->device = NULL;
+ }
+ if (nps->passwd != NULL) {
+ FREE(nps->passwd);
+ nps->passwd = NULL;
+ }
+ FREE(nps);
+}
+
+/* Create a new BayTech Stonith device. */
+
+static StonithPlugin *
+wti_nps_new(const char *subplugin)
+{
+ struct pluginDevice* nps = ST_MALLOCT(struct pluginDevice);
+
+ if (Debug) {
+ LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);
+ }
+
+ if (nps == NULL) {
+ LOG(PIL_CRIT, "out of memory");
+ return(NULL);
+ }
+ memset(nps, 0, sizeof(*nps));
+ nps->pluginid = pluginid;
+ nps->pid = -1;
+ nps->rdfd = -1;
+ nps->wrfd = -1;
+ nps->device = NULL;
+ nps->passwd = NULL;
+ nps->idinfo = DEVICE;
+ nps->sp.s_ops = &wti_npsOps;
+
+ return &(nps->sp);
+}
+