⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rps10.c

📁 linux集群服务器软件代码包
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $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 + -