?? rps10.c
字號:
/* $Id: rps10.c,v 1.19 2005/02/18 07:29:47 zhaokai Exp $ *//* * Stonith module for WTI Remote Power Controllers (RPS-10M device) * * Original code from baytech.c by * Copyright (c) 2000 Alan Robertson <alanr@unix.sh> * * Modifications for WTI RPS10 * Copyright (c) 2000 Computer Generation Incorporated * Eric Z. Ayers <eric.ayers@compgen.com> * * Mangled by Zhaokai <zhaokai@cn.ibm.com>, 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 * */#define DEVICE "WTI RPS10 Power Switch"#include "stonith_plugin_common.h"#include <termios.h>#define PIL_PLUGIN rps10#define PIL_PLUGIN_S "rps10"#define PIL_PLUGINLICENSE LICENSE_LGPL#define PIL_PLUGINLICENSEURL URL_LGPL#define ST_RPS10 "<serial_device> <node> <outlet> [ <node> <outlet> [...] ]"#define MAX_PRSID 256#include <pils/plugin.h>static StonithPlugin * rps10_new(void);static void rps10_destroy(StonithPlugin *);static int rps10_set_config(StonithPlugin *, StonithNVpair *);static const char** rps10_get_confignames(StonithPlugin *);static const char * rps10_getinfo(StonithPlugin * s, int InfoType);static int rps10_status(StonithPlugin * );static int rps10_reset_req(StonithPlugin * s, int request, const char * host);static char ** rps10_hostlist(StonithPlugin *);static struct stonith_ops rps10Ops ={ rps10_new, /* Create new STONITH object */ rps10_destroy, /* Destroy STONITH object */ rps10_getinfo, /* Return STONITH info string */ rps10_get_confignames, /* Return STONITH info string */ rps10_set_config, /* Get configuration from NVpairs */ rps10_status, /* Return STONITH device status */ rps10_reset_req, /* Request a reset */ rps10_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_signal.h"#define DOESNT_USE_STONITHKILLCOMM#define DOESNT_USE_STONITHSCANLINE#include "stonith_expect_helpers.h"PIL_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 , &rps10Ops , NULL /*close */ , &OurInterface , (void*)&OurImports , &interfprivate); }/* * This was written for a Western Telematic Inc. (WTI) * Remote Power Switch - RPS-10M. * * It has a DB9 serial port, a Rotary Address Switch, * and a pair of RJ-11 jacks for linking multiple switches * together. The 'M' unit is a master unit which can control * up to 9 additional slave units. (the master unit also has an * A/C outlet, so you can control up to 10 devices) * * There are a set of dip switches. The default shipping configuration * is with all dip switches down. I highly recommend that you flip * switch #3 up, so that when the device is plugged in, the power * to the unit comes on. * * The serial interface is fixed at 9600 BPS (well, you *CAN* * select 2400 BPS with a dip switch, but why?) 8-N-1 * * The ASCII command string is: * * ^B^X^X^B^X^Xac^M * * ^B^X^X^B^X^X "fixed password" prefix (CTRL-B CTRL-X ... ) * ^M the carriage return character * * a = 0-9 Indicates the address of the module to receive the command * a = * Sends the command to all modules * * c = 0 Switch the AC outlet OFF * Returns: * Plug 0 Off * Complete * * c = 1 Switch the AC outlet ON * Returns: * Plug 0 On * Complete * * c = T Toggle AC OFF (delay) then back ON * Returns: * Plug 0 Off * Plug 0 On * Complete * * c = ? Read and display status of the selected module * Returns: * Plug 0 On # or Plug 0 Off * Complete * * e.g. ^B^X^X^B^X^X0T^M toggles the power on plug 0 OFF and then ON * * 21 September 2000 * Eric Z. Ayers * Computer Generation, Inc. */struct cntrlr_str { char outlet_id; /* value 0-9, '*' */ char * node; /* name of the node attached to this outlet */};struct pluginDevice { StonithPlugin sp; const char * pluginid; char * idinfo; /* ??? What's this for Alan ??? */ char * unitid; /* ??? What's this for Alan ??? */ int fd; /* FD open to the serial port */ int config; /* 0 if not configured, 1 if configured with rps10_set_config_info() or rps10_set_config_file() */ char * device; /* Serial device name to use to communicate to this RPS10 */#define WTI_NUM_CONTROLLERS 10 struct cntrlr_str controllers[WTI_NUM_CONTROLLERS]; /* one master switch can address 10 controllers */ /* Number of actually configured units */ int unit_count;};/* This string is used to identify this type of object in the config file */static const char * pluginid = "WTI_RPS10";static const char * NOTwtiid = "OBJECT DESTROYED: (WTI RPS-10)";/* WTIpassword - The fixed string ^B^X^X^B^X^X */static const char WTIpassword[7] = {2,24,24,2,24,24,0}; #ifndef DEBUG#define DEBUG 0#endifstatic int gbl_debug = DEBUG;/* * Different expect strings that we get from the WTI_RPS10 * Remote Power Controllers... */static struct Etoken WTItokReady[] = { {"RPS-10 Ready", 0, 0}, {NULL,0,0}};static struct Etoken WTItokComplete[] = { {"Complete", 0, 0} ,{NULL,0,0}};static struct Etoken WTItokPlug[] = { {"Plug", 0, 0}, {NULL,0,0}};static struct Etoken WTItokOutlet[] = { {"0", 0, 0}, {"1", 0, 0}, {"2", 0, 0}, {"3", 0, 0}, {"4", 0, 0}, {"5", 0, 0}, {"6", 0, 0}, {"7", 0, 0}, {"8", 0, 0}, {"9", 0, 0}, {NULL,0,0}};static struct Etoken WTItokOff[] = { {"Off", 0, 0}, {NULL,0,0}};/* * Tokens currently not used because they don't show up on all RPS10 units: * */static struct Etoken WTItokOn[] = { {"On", 0, 0}, {NULL,0,0}};/* Accept either a CR/NL or an NL/CR */static struct Etoken WTItokCRNL[] = { {"\n\r",0,0},{"\r\n",0,0},{NULL,0,0}};static int RPSConnect(struct pluginDevice * ctx);static int RPSDisconnect(struct pluginDevice * ctx);static int RPSReset(struct pluginDevice*, char unit_id, const char * rebootid);#if defined(ST_POWERON) static int RPSOn(struct pluginDevice*, char unit_id, const char * rebootid);#endif#if defined(ST_POWEROFF) static int RPSOff(struct pluginDevice*, char unit_id, const char * rebootid);#endifstatic signed char RPSNametoOutlet ( struct pluginDevice * ctx, const char * host );static int RPS_parse_config_info(struct pluginDevice* ctx, const char * info);#define SENDCMD(outlet, cmd, timeout) { \ int return_val = RPSSendCommand(ctx, outlet, cmd, timeout); \ if (return_val != S_OK) return return_val; \ }/* * RPSSendCommand - send a command to the specified outlet */static intRPSSendCommand (struct pluginDevice *ctx, char outlet, char command, int timeout){ char writebuf[10]; /* all commands are 9 chars long! */ int return_val; /* system call result */ fd_set rfds, wfds, xfds; struct timeval tv; /* */ /* list of FDs for select() */ if (Debug) { LOG(PIL_DEBUG, "%s:called.", __FUNCTION__); } FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&xfds); snprintf (writebuf, sizeof(writebuf), "%s%c%c\r", WTIpassword, outlet, command); if (gbl_debug) printf ("Sending %s\n", writebuf); /* Make sure the serial port won't block on us. use select() */ FD_SET(ctx->fd, &wfds); FD_SET(ctx->fd, &xfds); tv.tv_sec = timeout; tv.tv_usec = 0; return_val = select(ctx->fd+1, NULL, &wfds,&xfds, &tv); if (return_val == 0) { /* timeout waiting on serial port */ LOG(PIL_CRIT, "%s: Timeout writing to %s", pluginid, ctx->device); return S_TIMEOUT; } else if ((return_val == -1) || FD_ISSET(ctx->fd, &xfds)) { /* an error occured */ LOG(PIL_CRIT, "%s: Error before writing to %s: %s", pluginid, ctx->device, strerror(errno)); return S_OOPS; } /* send the command */ if (write(ctx->fd, writebuf, strlen(writebuf)) != (int)strlen(writebuf)) { LOG(PIL_CRIT, "%s: Error writing to %s : %s", pluginid, ctx->device, strerror(errno)); return S_OOPS; } /* suceeded! */ return S_OK;} /* end RPSSendCommand() *//* * RPSReset - Reset (power-cycle) the given outlet id */static intRPSReset(struct pluginDevice* ctx, char unit_id, const char * rebootid){ if (Debug) { LOG(PIL_DEBUG, "%s:called.", __FUNCTION__); } if (gbl_debug) {printf ("Calling RPSReset (%s)\n", pluginid);} if (ctx->fd < 0) { LOG(PIL_CRIT, "%s: device %s is not open!", pluginid, ctx->device); return S_OOPS; } /* send the "toggle power" command */ SENDCMD(unit_id, 'T', 10); /* Expect "Plug 0 Off" */ /* Note: If asked to control "*", the RPS10 will report all units it * separately; however, we don't know how many, so we can only wait * for the first unit to report something and then wait until the * "Complete" */ EXPECT(ctx->fd, WTItokPlug, 5); if (gbl_debug) { printf ("Got Plug\n"); } EXPECT(ctx->fd, WTItokOutlet, 2); if (gbl_debug) { printf ("Got Outlet #\n"); } EXPECT(ctx->fd, WTItokOff, 2); if (gbl_debug) { printf ("Got Off\n"); } EXPECT(ctx->fd, WTItokCRNL, 2); LOG(PIL_INFO, "%s: %s",_("Host is being rebooted"), rebootid); /* Expect "Complete" */ EXPECT(ctx->fd, WTItokComplete, 14); if (gbl_debug) { printf ("Got Complete\n"); } EXPECT(ctx->fd, WTItokCRNL, 2); if (gbl_debug) { printf ("Got NL\n"); } return(S_OK);} /* end RPSReset() */#if defined(ST_POWERON) /* * RPSOn - Turn OFF the given outlet id */static intRPSOn(struct pluginDevice* ctx, char unit_id, const char * host){ if (Debug) { LOG(PIL_DEBUG , "%s:called.", __FUNCTION__); } if (ctx->fd < 0) { LOG(PIL_CRIT, "%s: device %s is not open!", pluginid, ctx->device); return S_OOPS; } /* send the "On" command */ SENDCMD(unit_id, '1', 10); /* Expect "Plug 0 On" */ EXPECT(ctx->fd, WTItokPlug, 5); EXPECT(ctx->fd, WTItokOutlet, 2); EXPECT(ctx->fd, WTItokOn, 2); EXPECT(ctx->fd, WTItokCRNL, 2); LOG(PIL_INFO, "%s: %s", _("Host is being turned on"), host); /* Expect "Complete" */ EXPECT(ctx->fd, WTItokComplete, 5); EXPECT(ctx->fd, WTItokCRNL, 2); return(S_OK);} /* end RPSOn() */#endif#if defined(ST_POWEROFF) /* * RPSOff - Turn Off the given outlet id */static intRPSOff(struct pluginDevice* ctx, char unit_id, const char * host){ if (Debug) { LOG(PIL_DEBUG, "%s:called.", __FUNCTION__); } if (ctx->fd < 0) { LOG(PIL_CRIT, "%s: device %s is not open!", pluginid, ctx->device); return S_OOPS; } /* send the "Off" command */ SENDCMD(unit_id, '0', 10); /* Expect "Plug 0 Off" */ EXPECT(ctx->fd, WTItokPlug, 5); EXPECT(ctx->fd, WTItokOutlet, 2); EXPECT(ctx->fd, WTItokOff, 2); EXPECT(ctx->fd, WTItokCRNL, 2); LOG(PIL_INFO, "%s: %s", _("Host is being turned on."), host); /* Expect "Complete" */ EXPECT(ctx->fd, WTItokComplete, 5); EXPECT(ctx->fd, WTItokCRNL, 2); return(S_OK);} /* end RPSOff() */#endif/* * rps10_status - API entry point to probe the status of the stonith device * (basically just "is it reachable and functional?", not the * status of the individual outlets) * * Returns: * S_OOPS - some error occured * S_OK - if the stonith device is reachable and online. */static intrps10_status(StonithPlugin *s){ struct pluginDevice* ctx; if (Debug) { LOG(PIL_DEBUG, "%s:called.", __FUNCTION__); } if (gbl_debug) { printf ("Calling rps10_status (%s)\n", pluginid); } ERRIFNOTCONFIGED(s,S_OOPS); ctx = (struct pluginDevice*) s; if (RPSConnect(ctx) != S_OK) { return(S_OOPS); } /* The "connect" really does enough work to see if the controller is alive... It verifies that it is returning RPS-10 Ready */ return(RPSDisconnect(ctx));}/* * rps10_hostlist - API entry point to return the list of hosts * for the devices on this WTI_RPS10 unit * * This type of device is configured from the config file, * so we don't actually have to connect to figure this * out, just peruse the 'ctx' structure. * Returns: * NULL on error * a malloced array, terminated with a NULL, * of null-terminated malloc'ed strings. */static char **rps10_hostlist(StonithPlugin *s){ char ** ret = NULL; /* list to return */ int i; int j; struct pluginDevice* ctx; if (Debug) { LOG(PIL_DEBUG, "%s:called.", __FUNCTION__); } if (gbl_debug) { printf ("Calling rps10_hostlist (%s)\n", pluginid); } ERRIFNOTCONFIGED(s,NULL); ctx = (struct pluginDevice*) s; if (ctx->unit_count >= 1) { ret = (char **)MALLOC((ctx->unit_count+1)*sizeof(char*)); if (ret == NULL) { LOG(PIL_CRIT, "out of memory"); return ret; } ret[ctx->unit_count]=NULL; /* null terminate the array */ for (i=0; i < ctx->unit_count; i++) { ret[i] = STRDUP(ctx->controllers[i].node); if (ret[i] == NULL) { for(j=0; j<i; j++) { FREE(ret[j]); } FREE(ret); ret = NULL; break; } } /* end for each possible outlet */ } /* end if any outlets are configured */ return(ret);} /* end si_hostlist() *//* * Parse the given configuration information, and stash * it away... * * The format of <info> for this module is: * <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ...
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -