/* * Stonith module for Human Operator Stonith device * * Copyright (c) 2001 Gregor Binder * * This module is largely based on the "NULL Stonith device", written * by Alan Robertson , using code by David C. Teigland * originally appeared in the GFS stomith * meatware agent. * * Mangled by Zhaokai , IBM, 2005 * * 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 #define DEVICE "Meatware STONITH device" #include "stonith_plugin_common.h" #define PIL_PLUGIN meatware #define PIL_PLUGIN_S "meatware" #define PIL_PLUGINLICENSE LICENSE_LGPL #define PIL_PLUGINLICENSEURL URL_LGPL #include static StonithPlugin * meatware_new(const char *); static void meatware_destroy(StonithPlugin *); static int meatware_set_config(StonithPlugin *, StonithNVpair *); static const char * const * meatware_get_confignames(StonithPlugin *); static const char * meatware_getinfo(StonithPlugin * s, int InfoType); static int meatware_status(StonithPlugin * ); static int meatware_reset_req(StonithPlugin * s, int request, const char * host); static char ** meatware_hostlist(StonithPlugin *); static struct stonith_ops meatwareOps ={ meatware_new, /* Create new STONITH object */ meatware_destroy, /* Destroy STONITH object */ meatware_getinfo, /* Return STONITH info string */ meatware_get_confignames,/* Return STONITH info string */ meatware_set_config, /* Get configuration from NVpairs */ meatware_status, /* Return STONITH device status */ meatware_reset_req, /* Request a reset */ meatware_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; 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 , &meatwareOps , NULL /*close */ , &OurInterface , (void*)&OurImports , &interfprivate); } /* * Meatware STONITH device. */ struct pluginDevice { StonithPlugin sp; const char * pluginid; const char * idinfo; char ** hostlist; int hostcount; }; static const char * pluginid = "MeatwareDevice-Stonith"; static const char * NOTpluginID = "Meatware device has been destroyed"; #include "stonith_config_xml.h" static const char *meatwareXML = XML_PARAMETERS_BEGIN XML_HOSTLIST_PARM XML_PARAMETERS_END; static int meatware_status(StonithPlugin *s) { ERRIFWRONGDEV(s,S_OOPS); return S_OK; } /* * Return the list of hosts configured for this Meat device */ static char ** meatware_hostlist(StonithPlugin *s) { struct pluginDevice* nd; ERRIFWRONGDEV(s,NULL); nd = (struct pluginDevice*) s; if (nd->hostcount < 0) { LOG(PIL_CRIT , "unconfigured stonith object in Meatware_list_hosts"); return(NULL); } return OurImports->CopyHostList((const char * const *)nd->hostlist); } /* * Parse the config information, and stash it away... */ static int Meat_parse_config_info(struct pluginDevice* nd, const char * info) { LOG(PIL_INFO , "parse config info info=%s",info); if (nd->hostcount >= 0) { return(S_OOPS); } nd->hostlist = OurImports->StringToHostList(info); if (nd->hostlist == NULL) { LOG(PIL_CRIT,"StringToHostList() failed"); return S_OOPS; } for (nd->hostcount = 0; nd->hostlist[nd->hostcount]; nd->hostcount++) { strdown(nd->hostlist[nd->hostcount]); } return(S_OK); } /* * Indicate that host must be power cycled manually. */ static int meatware_reset_req(StonithPlugin * s, int request, const char * host) { int fd, rc; const char * meatpipe_pr = HA_VARRUNDIR "/meatware"; /* if you intend to change this, modify meatclient.c as well */ char line[256], meatpipe[256]; char resp_addr[50], resp_mw[50], resp_result[50]; ERRIFWRONGDEV(s,S_OOPS); snprintf(meatpipe, 256, "%s.%s", meatpipe_pr, host); umask(0); unlink(meatpipe); rc = mkfifo(meatpipe, (S_IRUSR | S_IWUSR)); if (rc < 0) { LOG(PIL_CRIT, "cannot create FIFO for Meatware_reset_host"); return S_OOPS; } LOG(PIL_CRIT, "OPERATOR INTERVENTION REQUIRED to reset %s.", host); LOG(PIL_CRIT, "Run \"meatclient -c %s\" AFTER power-cycling the " "machine.", host); fd = open(meatpipe, O_RDONLY); if (fd < 0) { LOG(PIL_CRIT, "cannot open FIFO for Meatware_reset_host"); return S_OOPS; } alarm(600); memset(line, 0, 256); rc = read(fd, line, 256); alarm(0); if (rc < 0) { LOG(PIL_CRIT, "read error on FIFO for Meatware_reset_host"); return S_OOPS; } memset(resp_mw, 0, 50); memset(resp_result, 0, 50); memset(resp_addr, 0, 50); if (sscanf(line, "%s %s %s", resp_mw, resp_result, resp_addr) < 3) { LOG(PIL_CRIT, "Format error - failed to Meatware-reset node %s", host); return S_RESETFAIL; } strdown(resp_addr); if (strncmp(resp_mw, "meatware", 8) || strncmp(resp_result, "reply", 5) || strncasecmp(resp_addr, host, strlen(resp_addr))) { LOG(PIL_CRIT, "failed to Meatware-reset node %s", host); return S_RESETFAIL; }else{ LOG(PIL_INFO, "node Meatware-reset: %s", host); unlink(meatpipe); return S_OK; } } /* * Parse the information in the given string * and stash it away... */ static int meatware_set_config(StonithPlugin* s, StonithNVpair *list) { struct pluginDevice* nd; int rc; StonithNamesToGet namestocopy [] = { {ST_HOSTLIST, NULL} , {NULL, NULL} }; ERRIFWRONGDEV(s,S_OOPS); nd = (struct pluginDevice*) s; if ((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK) { return rc; } rc = Meat_parse_config_info(nd, namestocopy[0].s_value); FREE(namestocopy[0].s_value); return rc; } /* * Return STONITH config vars */ static const char * const * meatware_get_confignames(StonithPlugin* p) { static const char * MeatwareParams[] = {ST_HOSTLIST, NULL }; return MeatwareParams; } /* * Return STONITH info string */ static const char * meatware_getinfo(StonithPlugin * s, int reqtype) { struct pluginDevice* nd; const char * ret; ERRIFWRONGDEV(s,NULL); /* * We look in the ST_TEXTDOMAIN catalog for our messages */ nd = (struct pluginDevice *)s; switch (reqtype) { case ST_DEVICEID: ret = nd->idinfo; break; case ST_DEVICENAME: ret = "Your Name Here"; break; case ST_DEVICEDESCR: ret = "Human (meatware) intervention STONITH device.\n" "This STONITH agent prompts a human to reset a machine.\n" "The human tells it when the reset was completed."; break; case ST_CONF_XML: /* XML metadata */ ret = meatwareXML; break; default: ret = NULL; break; } return ret; } /* * Meat Stonith destructor... */ static void meatware_destroy(StonithPlugin *s) { struct pluginDevice* nd; VOIDERRIFWRONGDEV(s); nd = (struct pluginDevice *)s; nd->pluginid = NOTpluginID; if (nd->hostlist) { stonith_free_hostlist(nd->hostlist); nd->hostlist = NULL; } nd->hostcount = -1; FREE(nd); } /* Create a new Meatware Stonith device. */ static StonithPlugin * meatware_new(const char *subplugin) { struct pluginDevice* nd = ST_MALLOCT(struct pluginDevice); if (nd == NULL) { LOG(PIL_CRIT, "out of memory"); return(NULL); } memset(nd, 0, sizeof(*nd)); nd->pluginid = pluginid; nd->hostlist = NULL; nd->hostcount = -1; nd->idinfo = DEVICE; nd->sp.s_ops = &meatwareOps; return &(nd->sp); }