You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
heartbeat/lib/plugins/stonith/baytech.c

925 lines
21 KiB

/*
* Stonith module for BayTech Remote Power Controllers (RPC-x devices)
*
* Copyright (c) 2000 Alan Robertson <alanr@unix.sh>
*
* 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 <lha_internal.h>
#define DEVICE "BayTech power switch"
#define DOESNT_USE_STONITHKILLCOMM 1
#include "stonith_plugin_common.h"
#define PIL_PLUGIN baytech
#define PIL_PLUGIN_S "baytech"
#define PIL_PLUGINLICENSE LICENSE_LGPL
#define PIL_PLUGINLICENSEURL URL_LGPL
#include <pils/plugin.h>
#include "stonith_signal.h"
static StonithPlugin * baytech_new(const char *);
static void baytech_destroy(StonithPlugin *);
static int baytech_set_config(StonithPlugin *, StonithNVpair *);
static const char ** baytech_get_confignames(StonithPlugin * s);
static const char * baytech_get_info(StonithPlugin * s, int InfoType);
static int baytech_status(StonithPlugin *);
static int baytech_reset_req(StonithPlugin * s, int request, const char * host);
static char ** baytech_hostlist(StonithPlugin *);
static struct stonith_ops baytechOps ={
baytech_new, /* Create new STONITH object */
baytech_destroy, /* Destroy STONITH object */
baytech_get_info, /* Return STONITH info string */
baytech_get_confignames, /* Return STONITH config vars */
baytech_set_config, /* set configuration from vars */
baytech_status, /* Return STONITH device status */
baytech_reset_req, /* Request a reset */
baytech_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"
#define MAXOUTLET 32
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
, &baytechOps
, NULL /*close */
, &OurInterface
, (void*)&OurImports
, &interfprivate);
}
/*
* I have an RPC-5. This code has been tested with this switch.
*
* The BayTech switches are quite nice, but the dialogues are a bit of a
* pain for mechanical parsing.
*/
struct pluginDevice {
StonithPlugin sp;
const char * pluginid;
char * idinfo;
char * unitid;
const struct BayTechModelInfo* modelinfo;
pid_t pid;
int rdfd;
int wrfd;
char * device;
char * user;
char * passwd;
};
struct BayTechModelInfo {
const char * type; /* Baytech model info */
size_t socklen; /* Length of socket name string */
struct Etoken * expect; /* Expect string before outlet list */
};
static int parse_socket_line(struct pluginDevice*,const char *
, int *, char *);
static const char * pluginid = "BayTech-Stonith";
static const char * NOTpluginID = "BayTech device has been destroyed";
/*
* Different expect strings that we get from the Baytech
* Remote Power Controllers...
*/
#define BAYTECHASSOC "Bay Technical Associates"
static struct Etoken BayTechAssoc[] = { {BAYTECHASSOC, 0, 0}, {NULL,0,0}};
static struct Etoken UnitId[] = { {"Unit ID: ", 0, 0}, {NULL,0,0}};
static struct Etoken login[] = { {"username>", 0, 0} ,{NULL,0,0}};
static struct Etoken password[] = { {"password>", 0, 0}
, {"username>", 0, 0} ,{NULL,0,0}};
static struct Etoken Selection[] = { {"election>", 0, 0} ,{NULL,0,0}};
static struct Etoken RPC[] = { {"RPC", 0, 0} ,{NULL,0,0}};
static struct Etoken LoginOK[] = { {"RPC", 0, 0}, {"Invalid password", 1, 0}
, {NULL,0,0}};
static struct Etoken GTSign[] = { {">", 0, 0} ,{NULL,0,0}};
static struct Etoken Menu[] = { {"Menu:", 0, 0} ,{NULL,0,0}};
static struct Etoken Temp[] = { {"emperature: ", 0, 0}
, {NULL,0,0}};
static struct Etoken Break[] = { {"Status", 0, 0}
, {NULL,0,0}};
static struct Etoken PowerApplied[] = { {"ower applied to outlet", 0, 0}
, {NULL,0,0}};
/* We may get a notice about rebooting, or a request for confirmation */
static struct Etoken Rebooting[] = { {"ebooting selected outlet", 0, 0}
, {"(Y/N)>", 1, 0}
, {"already off.", 2, 0}
, {NULL,0,0}};
static struct Etoken TurningOnOff[] = { {"RPC", 0, 0}
, {"(Y/N)>", 1, 0}
, {"already ", 2, 0}
, {NULL,0,0}};
static struct BayTechModelInfo ModelInfo [] = {
{"BayTech RPC-5", 18, Temp},/* This first model will be the default */
{"BayTech RPC-3", 10, Break},
{"BayTech RPC-3A", 10, Break},
{NULL, 0, NULL},
};
#include "stonith_config_xml.h"
static const char *baytechXML =
XML_PARAMETERS_BEGIN
XML_IPADDR_PARM
XML_LOGIN_PARM
XML_PASSWD_PARM
XML_PARAMETERS_END;
static int RPC_connect_device(struct pluginDevice * bt);
static int RPCLogin(struct pluginDevice * bt);
static int RPCRobustLogin(struct pluginDevice * bt);
static int RPCNametoOutletList(struct pluginDevice*, const char * name
, int outletlist[]);
static int RPCReset(struct pluginDevice*, int unitnum, const char * rebootid);
static int RPCLogout(struct pluginDevice * bt);
static int RPC_onoff(struct pluginDevice*, int unitnum, const char * unitid
, int request);
/* Login to the Baytech Remote Power Controller (RPC) */
static int
RPCLogin(struct pluginDevice * bt)
{
char IDinfo[128];
static char IDbuf[128];
char * idptr = IDinfo;
char * delim;
int j;
EXPECT(bt->rdfd, RPC, 10);
/* Look for the unit type info */
if (EXPECT_TOK(bt->rdfd, BayTechAssoc, 2, IDinfo
, sizeof(IDinfo), Debug) < 0) {
LOG(PIL_CRIT, "No initial response from %s.", bt->idinfo);
return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
}
idptr += strspn(idptr, WHITESPACE);
/*
* We should be looking at something like this:
* RPC-5 Telnet Host
* Revision F 4.22, (C) 1999
* Bay Technical Associates
*/
/* Truncate the result after the RPC-5 part */
if ((delim = strchr(idptr, ' ')) != NULL) {
*delim = EOS;
}
snprintf(IDbuf, sizeof(IDbuf), "BayTech RPC%s", idptr);
REPLSTR(bt->idinfo, IDbuf);
if (bt->idinfo == NULL) {
return(S_OOPS);
}
bt->modelinfo = &ModelInfo[0];
for (j=0; ModelInfo[j].type != NULL; ++j) {
/*
* TIMXXX -
* Look at device ID as this really describes the model.
*/
if (strcasecmp(ModelInfo[j].type, IDbuf) == 0) {
bt->modelinfo = &ModelInfo[j];
break;
}
}
/* Look for the unit id info */
EXPECT(bt->rdfd, UnitId, 10);
SNARF(bt->rdfd, IDbuf, 2);
delim = IDbuf + strcspn(IDbuf, WHITESPACE);
*delim = EOS;
REPLSTR(bt->unitid, IDbuf);
if (bt->unitid == NULL) {
return(S_OOPS);
}
/* Expect "username>" */
EXPECT(bt->rdfd, login, 2);
SEND(bt->wrfd, bt->user);
SEND(bt->wrfd, "\r");
/* Expect "password>" */
switch (StonithLookFor(bt->rdfd, password, 5)) {
case 0: /* Good! */
break;
case 1: /* OOPS! got another username prompt */
LOG(PIL_CRIT, "Invalid username for %s.", bt->idinfo);
return(S_ACCESS);
default:
return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
}
SEND(bt->wrfd, bt->passwd);
SEND(bt->wrfd, "\r");
/* Expect "RPC-x Menu" */
switch (StonithLookFor(bt->rdfd, LoginOK, 5)) {
case 0: /* Good! */
break;
case 1: /* Uh-oh - bad password */
LOG(PIL_CRIT, "Invalid password for %s.", bt->idinfo);
return(S_ACCESS);
default:
return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
}
EXPECT(bt->rdfd, Menu, 2);
return(S_OK);
}
static int
RPCRobustLogin(struct pluginDevice * bt)
{
int rc=S_OOPS;
int j;
for (j=0; j < 20 && rc != S_OK; ++j) {
if (RPC_connect_device(bt) != S_OK) {
continue;
}
rc = RPCLogin(bt);
}
return rc;
}
/* Log out of the Baytech RPC */
static int
RPCLogout(struct pluginDevice* bt)
{
int rc;
/* Make sure we're in the right menu... */
SEND(bt->wrfd, "\r");
/* Expect "Selection>" */
rc = StonithLookFor(bt->rdfd, Selection, 5);
/* Option 6 is Logout */
SEND(bt->wrfd, "6\r");
close(bt->wrfd);
close(bt->rdfd);
bt->wrfd = bt->rdfd = -1;
return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));
}
/* Reset (power-cycle) the given outlet number */
static int
RPCReset(struct pluginDevice* bt, int unitnum, const char * rebootid)
{
char unum[32];
SEND(bt->wrfd, "\r");
/* Make sure we're in the top level menu */
/* Expect "RPC-x Menu" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, Menu, 5);
/* OK. Request sub-menu 1 (Outlet Control) */
SEND(bt->wrfd, "1\r");
/* Verify that we're in the sub-menu */
/* Expect: "RPC-x>" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, GTSign, 5);
/* Send REBOOT command for given outlet */
snprintf(unum, sizeof(unum), "REBOOT %d\r", unitnum);
SEND(bt->wrfd, unum);
/* Expect "ebooting "... or "(Y/N)" (if confirmation turned on) */
retry:
switch (StonithLookFor(bt->rdfd, Rebooting, 5)) {
case 0: /* Got "Rebooting" Do nothing */
break;
case 1: /* Got that annoying command confirmation :-( */
SEND(bt->wrfd, "Y\r");
goto retry;
case 2: /* Outlet is turned off */
LOG(PIL_CRIT, "Host is OFF: %s.", rebootid);
return(S_ISOFF);
default:
return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
}
LOG(PIL_INFO, "Host %s (outlet %d) being rebooted."
, rebootid, unitnum);
/* Expect "ower applied to outlet" */
if (StonithLookFor(bt->rdfd, PowerApplied, 30) < 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 (outlet %d)."
, rebootid, unitnum);
/* Expect: "RPC-x>" */
EXPECT(bt->rdfd, RPC,5);
EXPECT(bt->rdfd, GTSign, 5);
/* Pop back to main menu */
SEND(bt->wrfd, "MENU\r");
return(S_OK);
}
static int
RPC_onoff(struct pluginDevice* bt, int unitnum, const char * unitid, int req)
{
char unum[32];
const char * onoff = (req == ST_POWERON ? "on" : "off");
int rc;
if ((rc = RPCRobustLogin(bt) != S_OK)) {
LOG(PIL_CRIT, "Cannot log into %s."
, bt->idinfo ? bt->idinfo : DEVICE);
return(rc);
}
SEND(bt->wrfd, "\r");
/* Make sure we're in the top level menu */
/* Expect "RPC-x Menu" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, Menu, 5);
/* OK. Request sub-menu 1 (Outlet Control) */
SEND(bt->wrfd, "1\r");
/* Verify that we're in the sub-menu */
/* Expect: "RPC-x>" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, GTSign, 5);
/* Send ON/OFF command for given outlet */
snprintf(unum, sizeof(unum), "%s %d\r"
, onoff, unitnum);
SEND(bt->wrfd, unum);
/* Expect "RPC->x "... or "(Y/N)" (if confirmation turned on) */
if (StonithLookFor(bt->rdfd, TurningOnOff, 10) == 1) {
/* They've turned on that annoying command confirmation :-( */
SEND(bt->wrfd, "Y\r");
EXPECT(bt->rdfd, TurningOnOff, 10);
}
EXPECT(bt->rdfd, GTSign, 10);
/* All Right! Command done. Life is Good! */
LOG(PIL_INFO, "Power to host %s (outlet %d) turned %s."
, unitid, unitnum, onoff);
/* Pop back to main menu */
SEND(bt->wrfd, "MENU\r");
return(S_OK);
}
/*
* Map the given host name into an (AC) Outlet number on the power strip
*/
static int
RPCNametoOutletList(struct pluginDevice* bt, const char * name
, int outletlist[])
{
char NameMapping[128];
int sockno;
char sockname[32];
int maxfound = 0;
/* Verify that we're in the top-level menu */
SEND(bt->wrfd, "\r");
/* Expect "RPC-x Menu" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, Menu, 5);
/* OK. Request sub-menu 1 (Outlet Control) */
SEND(bt->wrfd, "1\r");
/* Verify that we're in the sub-menu */
/* Expect: "RPC-x>" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, GTSign, 5);
/* The status command output contains mapping of hosts to outlets */
SEND(bt->wrfd, "STATUS\r");
/* Expect: "emperature:" so we can skip over it... */
EXPECT(bt->rdfd, bt->modelinfo->expect, 5);
EXPECT(bt->rdfd, CRNL, 5);
/* Looks Good! Parse the status output */
do {
char * last;
NameMapping[0] = EOS;
SNARF(bt->rdfd, NameMapping, 5);
if (!parse_socket_line(bt, NameMapping, &sockno, sockname)) {
continue;
}
last = sockname+bt->modelinfo->socklen;
*last = EOS;
--last;
/* Strip off trailing blanks */
for(; last > sockname; --last) {
if (*last == ' ') {
*last = EOS;
}else{
break;
}
}
if (strcasecmp(name, sockname) == 0) {
outletlist[maxfound] = sockno;
++maxfound;
}
} while (strlen(NameMapping) > 2 && maxfound < MAXOUTLET);
/* Pop back out to the top level menu */
SEND(bt->wrfd, "MENU\r");
return(maxfound);
}
static int
baytech_status(StonithPlugin *s)
{
struct pluginDevice* bt;
int rc;
ERRIFNOTCONFIGED(s,S_OOPS);
bt = (struct pluginDevice*) s;
if ((rc = RPCRobustLogin(bt) != S_OK)) {
LOG(PIL_CRIT, "Cannot log into %s."
, bt->idinfo ? bt->idinfo : DEVICE);
return(rc);
}
/* Verify that we're in the top-level menu */
SEND(bt->wrfd, "\r");
/* Expect "RPC-x Menu" */
EXPECT(bt->rdfd, RPC, 5);
EXPECT(bt->rdfd, Menu, 5);
return(RPCLogout(bt));
}
/*
* Return the list of hosts (outlet names) for the devices on this BayTech unit
*/
static char **
baytech_hostlist(StonithPlugin *s)
{
char NameMapping[128];
char* NameList[64];
unsigned int numnames = 0;
char ** ret = NULL;
struct pluginDevice* bt;
unsigned int i;
ERRIFNOTCONFIGED(s,NULL);
bt = (struct pluginDevice*) s;
if (RPCRobustLogin(bt) != S_OK) {
LOG(PIL_CRIT, "Cannot log into %s."
, bt->idinfo ? bt->idinfo : DEVICE);
return(NULL);
}
/* Verify that we're in the top-level menu */
SEND(bt->wrfd, "\r");
/* Expect "RPC-x Menu" */
NULLEXPECT(bt->rdfd, RPC, 5);
NULLEXPECT(bt->rdfd, Menu, 5);
/* OK. Request sub-menu 1 (Outlet Control) */
SEND(bt->wrfd, "1\r");
/* Verify that we're in the sub-menu */
/* Expect: "RPC-x>" */
NULLEXPECT(bt->rdfd, RPC, 5);
NULLEXPECT(bt->rdfd, GTSign, 5);
/* The status command output contains mapping of hosts to outlets */
SEND(bt->wrfd, "STATUS\r");
/* Expect: "emperature:" so we can skip over it... */
NULLEXPECT(bt->rdfd, bt->modelinfo->expect, 5);
NULLEXPECT(bt->rdfd, CRNL, 5);
/* Looks Good! Parse the status output */
do {
int sockno;
char sockname[64];
char * last;
char * nm;
NameMapping[0] = EOS;
NULLSNARF(bt->rdfd, NameMapping, 5);
if (!parse_socket_line(bt, NameMapping, &sockno, sockname)) {
continue;
}
last = sockname+bt->modelinfo->socklen;
*last = EOS;
--last;
/* Strip off trailing blanks */
for(; last > sockname; --last) {
if (*last == ' ') {
*last = EOS;
}else{
break;
}
}
if (numnames >= DIMOF(NameList)-1) {
break;
}
if ((nm = (char*)STRDUP(sockname)) == NULL) {
goto out_of_memory;
}
g_strdown(nm);
NameList[numnames] = nm;
++numnames;
NameList[numnames] = NULL;
} while (strlen(NameMapping) > 2);
/* Pop back out to the top level menu */
SEND(bt->wrfd, "MENU\r");
if (numnames >= 1) {
ret = (char **)MALLOC((numnames+1)*sizeof(char*));
if (ret == NULL) {
goto out_of_memory;
}else{
memcpy(ret, NameList, (numnames+1)*sizeof(char*));
}
}
(void)RPCLogout(bt);
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 BayTech device.
* We should add serial support here eventually...
*/
static int
RPC_connect_device(struct pluginDevice * bt)
{
int fd = OurImports->OpenStreamSocket(bt->device
, TELNET_PORT, TELNET_SERVICE);
if (fd < 0) {
return(S_OOPS);
}
bt->rdfd = bt->wrfd = fd;
return(S_OK);
}
/*
* Reset the given host on this Stonith device.
*/
static int
baytech_reset_req(StonithPlugin * s, int request, const char * host)
{
int rc = S_OK;
int lorc = 0;
struct pluginDevice* bt;
ERRIFNOTCONFIGED(s,S_OOPS);
bt = (struct pluginDevice*) s;
if ((rc = RPCRobustLogin(bt)) != S_OK) {
LOG(PIL_CRIT, "Cannot log into %s."
, bt->idinfo ? bt->idinfo : DEVICE);
}else{
int noutlets;
int outlets[MAXOUTLET];
int j;
noutlets = RPCNametoOutletList(bt, host, outlets);
if (noutlets < 1) {
LOG(PIL_CRIT, "%s %s doesn't control host [%s]"
, bt->idinfo, bt->unitid, host);
return(S_BADHOST);
}
switch(request) {
case ST_POWERON:
case ST_POWEROFF:
for (j=0; rc == S_OK && j < noutlets;++j) {
rc = RPC_onoff(bt, outlets[j], host, request);
}
break;
case ST_GENERIC_RESET:
/*
* Our strategy here:
* 1. Power off all outlets except the last one
* 2. reset the last outlet
* 3. power the other outlets back on
*/
for (j=0; rc == S_OK && j < noutlets-1; ++j) {
rc = RPC_onoff(bt,outlets[j],host
, ST_POWEROFF);
}
if (rc == S_OK) {
rc = RPCReset(bt, outlets[j], host);
}
for (j=0; rc == S_OK && j < noutlets-1; ++j) {
rc = RPC_onoff(bt, outlets[j], host
, ST_POWERON);
}
break;
default:
rc = S_INVAL;
break;
}
}
lorc = RPCLogout(bt);
return(rc != S_OK ? rc : lorc);
}
static const char **
baytech_get_confignames(StonithPlugin * s)
{
static const char * ret[] = {ST_IPADDR, ST_LOGIN, ST_PASSWD, NULL};
return ret;
}
/*
* Parse the config information in the given string, and stash it away...
*/
static int
baytech_set_config(StonithPlugin* s, StonithNVpair* list)
{
struct pluginDevice* bt = (struct pluginDevice *)s;
int rc;
StonithNamesToGet namestocopy [] =
{ {ST_IPADDR, NULL}
, {ST_LOGIN, NULL}
, {ST_PASSWD, NULL}
, {NULL, NULL}
};
ERRIFWRONGDEV(s, S_OOPS);
if (bt->sp.isconfigured) {
return S_OOPS;
}
if ((rc =OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
return rc;
}
bt->device = namestocopy[0].s_value;
bt->user = namestocopy[1].s_value;
bt->passwd = namestocopy[2].s_value;
return(S_OK);
}
static const char *
baytech_get_info(StonithPlugin * s, int reqtype)
{
struct pluginDevice* bt;
const char * ret;
ERRIFWRONGDEV(s,NULL);
bt = (struct pluginDevice *)s;
switch (reqtype) {
case ST_DEVICEID: /* What type of device? */
ret = bt->idinfo;
break;
case ST_DEVICENAME: /* Which particular device? */
ret = bt->device;
break;
case ST_DEVICEDESCR: /* Description of dev type */
ret = "Bay Technical Associates (Baytech) RPC "
"series power switches (via telnet).\n"
"The RPC-5, RPC-3 and RPC-3A switches are well tested"
".";
break;
case ST_DEVICEURL: /* Manufacturer's web site */
ret = "http://www.baytech.net/";
break;
case ST_CONF_XML: /* XML metadata */
ret = baytechXML;
break;
default:
ret = NULL;
break;
}
return ret;
}
/*
* Baytech Stonith destructor...
*/
static void
baytech_destroy(StonithPlugin *s)
{
struct pluginDevice* bt;
VOIDERRIFWRONGDEV(s);
bt = (struct pluginDevice *)s;
bt->pluginid = NOTpluginID;
if (bt->rdfd >= 0) {
close(bt->rdfd);
bt->rdfd = -1;
}
if (bt->wrfd >= 0) {
close(bt->wrfd);
bt->wrfd = -1;
}
if (bt->device != NULL) {
FREE(bt->device);
bt->device = NULL;
}
if (bt->user != NULL) {
FREE(bt->user);
bt->user = NULL;
}
if (bt->passwd != NULL) {
FREE(bt->passwd);
bt->passwd = NULL;
}
if (bt->idinfo != NULL) {
FREE(bt->idinfo);
bt->idinfo = NULL;
}
if (bt->unitid != NULL) {
FREE(bt->unitid);
bt->unitid = NULL;
}
FREE(bt);
}
/* Create a new BayTech Stonith device. */
static StonithPlugin *
baytech_new(const char *subplugin)
{
struct pluginDevice* bt = ST_MALLOCT(struct pluginDevice);
if (bt == NULL) {
LOG(PIL_CRIT, "out of memory");
return(NULL);
}
memset(bt, 0, sizeof(*bt));
bt->pluginid = pluginid;
bt->pid = -1;
bt->rdfd = -1;
bt->wrfd = -1;
REPLSTR(bt->idinfo, DEVICE);
if (bt->idinfo == NULL) {
FREE(bt);
return(NULL);
}
bt->modelinfo = &ModelInfo[0];
bt->sp.s_ops = &baytechOps;
return &(bt->sp); /* same as "bt" */
}
static int
parse_socket_line(struct pluginDevice * bt, const char *NameMapping
, int *sockno, char *sockname)
{
#if 0
char format[64];
snprintf(format, sizeof(format), "%%7d %%%dc"
, bt->modelinfo->socklen);
/* 7 digits, 7 blanks, then 'socklen' characters */
/* [0-6]: digits, NameMapping[13] begins the sockname */
/* NameMapping strlen must be >= socklen + 14 */
if (sscanf(NameMapping, format, sockno, sockname) != 2) {
return FALSE;
}
#else
# define OFFSET 14
if (sscanf(NameMapping, "%7d", sockno) != 1
|| strlen(NameMapping) < OFFSET+bt->modelinfo->socklen) {
return FALSE;
}
strncpy(sockname, NameMapping+OFFSET, bt->modelinfo->socklen);
sockname[bt->modelinfo->socklen] = EOS;
#endif
return TRUE;
}