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

📄 baytech.c

📁 在LINUX下实现HA的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: baytech.c,v 1.13.2.1 2004/04/20 08:50:06 alan Exp $ *//* *	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 <portability.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <syslog.h>#include <libintl.h>#include <sys/wait.h>#include <glib.h>#include <stonith/stonith.h>#define PIL_PLUGINTYPE          STONITH_TYPE#define PIL_PLUGINTYPE_S        STONITH_TYPE_S#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"/* * baytechclosepi is called as part of unloading the baytech STONITH plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */static voidbaytechclosepi(PILPlugin*pi){}/* * baytechcloseintf called as part of shutting down the baytech STONITH * interface.  If there was any global data allocated, or file descriptors * opened, etc.  which is associated with the baytech implementation, * here's our chance to clean it up. */static PIL_rcbaytechcloseintf(PILInterface* pi, void* pd){	return PIL_OK;}static void *		baytech_new(void);static void		baytech_destroy(Stonith *);static int		baytech_set_config_file(Stonith *, const char * cfgname);static int		baytech_set_config_info(Stonith *, const char * info);static const char *	baytech_getinfo(Stonith * s, int InfoType);static int		baytech_status(Stonith * );static int		baytech_reset_req(Stonith * s, int request, const char * host);static char **		baytech_hostlist(Stonith  *);static void		baytech_free_hostlist(char **);static struct stonith_ops baytechOps ={	baytech_new,		/* Create new STONITH object	*/	baytech_destroy,		/* Destroy STONITH object	*/	baytech_set_config_file,	/* set configuration from file	*/	baytech_set_config_info,	/* Get configuration from file	*/	baytech_getinfo,		/* Return STONITH info string	*/	baytech_status,			/* Return STONITH device status	*/	baytech_reset_req,		/* Request a reset */	baytech_hostlist,		/* Return list of supported hosts */	baytech_free_hostlist		/* free above list */};PIL_PLUGIN_BOILERPLATE("1.0", Debug, baytechclosepi);static const PILPluginImports*  PluginImports;static PILPlugin*               OurPlugin;static PILInterface*		OurInterface;static StonithImports*		OurImports;static void*			interfprivate;#define LOG		PluginImports->log#define MALLOC		PluginImports->alloc#define STRDUP  	PluginImports->mstrdup#define FREE		PluginImports->mfree#define EXPECT_TOK	OurImports->ExpectToken#define STARTPROC	OurImports->StartProcessPIL_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	,	&baytechOps	,	baytechcloseintf		/*close */	,	&OurInterface	,	(void*)&OurImports	,	&interfprivate); }#define	DEVICE	"BayTech power switch"#define N_(text)	(text)#define _(text)		dgettext(ST_TEXTDOMAIN, text)/* *	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 BayTech {	const char *			BTid;	char *				idinfo;	char *				unitid;	const struct BayTechModelInfo*	modelinfo;	pid_t				pid;	int				rdfd;	int				wrfd;	int				config;	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 BayTech*,const char *,			int *, char *);static const char * BTid = "BayTech-Stonith";static const char * NOTbtid = "Hey, dummy this has been destroyed (BayTech)";#define	ISBAYTECH(i)	(((i)!= NULL && (i)->pinfo != NULL)	\	&& ((struct BayTech *)(i->pinfo))->BTid == BTid)#ifndef MALLOCT#	define MALLOCT(t) ((t *)(MALLOC(sizeof(t))))#endif#define	ISCONFIGED(i)	(ISBAYTECH(i) && ((struct BayTech *)(i->pinfo))->config)#define WHITESPACE	" \t\n\r\f"#define	REPLSTR(s,v)	{					\			if ((s) != NULL) {			\				FREE(s);			\				(s)=NULL;			\			}					\			(s) = STRDUP(v);			\			if ((s) == NULL) {			\				syslog(LOG_ERR, _("out of memory"));\			}					\			}/* *	Different expect strings that we get from the Baytech *	Remote Power Controllers... */#define BAYTECHASSOC	"Bay Technical Associates"static struct Etoken EscapeChar[] =	{ {"Escape character is '^]'.", 0, 0}					,	{NULL,0,0}};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[] =		{ {"reaker: ", 0, 0}					,	{NULL,0,0}};static struct Etoken PowerApplied[] =	{ {"ower applied to outlet", 0, 0}					,	{NULL,0,0}};/* Accept either a CR/NL or an NL/CR */static struct Etoken CRNL[] =		{ {"\n\r",0,0},{"\r\n",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 BayTechModelInfo ModelInfo [] = {	{"RPC-5", 18, Temp},	/* This first model will be the default */	{"RPC-3", 10, Break},		{"RPC-3A", 10, Break},	{NULL, 0, NULL},};static int	RPCLookFor(struct BayTech* bt, struct Etoken * tlist, int timeout);static int	RPC_connect_device(struct BayTech * bt);static int	RPCLogin(struct BayTech * bt);static int	RPCRobustLogin(struct BayTech * bt);static int	RPCNametoOutlet(struct BayTech*, const char * name);static int	RPCReset(struct BayTech*, int unitnum, const char * rebootid);static int	RPCScanLine(struct BayTech* bt, int timeout, char * buf, int max);static int	RPCLogout(struct BayTech * bt);static void	RPCkillcomm(struct BayTech * bt);static int	RPC_parse_config_info(struct BayTech* bt, const char * info);#if defined(ST_POWERON) && defined(ST_POWEROFF)static int	RPC_onoff(struct BayTech*, int unitnum, const char * unitid,		int request);#endif/* *	We do these things a lot.  Here are a few shorthand macros. */#define	SEND(s)	(write(bt->wrfd, (s), strlen(s)))#define	EXPECT(p,t)	{						\			if (RPCLookFor(bt, p, t) < 0)			\				return(errno == ETIMEDOUT			\			?	S_TIMEOUT : S_OOPS);			\			}#define	NULLEXPECT(p,t)	{						\				if (RPCLookFor(bt, p, t) < 0)		\					return(NULL);			\			}#define	SNARF(s, to)	{						\				if (RPCScanLine(bt,to,(s),sizeof(s))	\				!=	S_OK)				\					return(S_OOPS);			\			}#define	NULLSNARF(s, to)	{					\				if (RPCScanLine(bt,to,(s),sizeof(s))	\				!=	S_OK)				\					return(NULL);			\				}/* Look for any of the given patterns.  We don't care which */#define	MAXSAVE	512static intRPCLookFor(struct BayTech* bt, struct Etoken * tlist, int timeout){	int	rc;	char	savebuf[MAXSAVE];	savebuf[MAXSAVE-1] = EOS;	savebuf[0] = EOS;	if ((rc = EXPECT_TOK(bt->rdfd, tlist, timeout, savebuf, MAXSAVE)) < 0){		syslog(LOG_ERR, _("Did not find string: '%s' from " DEVICE ".")		,	tlist[0].string);		syslog(LOG_ERR, _("Got '%s' from " DEVICE " instead.")		,	savebuf);		RPCkillcomm(bt);		return(-1);	}#if 0	syslog(LOG_INFO	,	"BayTech: Expecting [%s] Received [%s]"	,	tlist[0].string	,	savebuf);#endif	return(rc);}/* Read and return the rest of the line */static intRPCScanLine(struct BayTech* bt, int timeout, char * buf, int max){	if (EXPECT_TOK(bt->rdfd, CRNL, timeout, buf, max) < 0) {		syslog(LOG_ERR, ("Could not read line from " DEVICE "."));		RPCkillcomm(bt);		bt->pid = -1;		return(S_OOPS);	}	return(S_OK);}/* Login to the Baytech Remote Power Controller (RPC) */static intRPCLogin(struct BayTech * bt){	char		IDinfo[128];	static char	IDbuf[128];	char *		idptr = IDinfo;	char *		delim;	int		j;	EXPECT(EscapeChar, 10);	/* Look for the unit type info */	if (EXPECT_TOK(bt->rdfd, BayTechAssoc, 2, IDinfo	,	sizeof(IDinfo)) < 0) {		syslog(LOG_ERR, _("No initial response from " DEVICE "."));		RPCkillcomm(bt);		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 %s", idptr);	REPLSTR(bt->idinfo, IDbuf);	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, idptr) == 0) {			bt->modelinfo = &ModelInfo[j];			break;		}	}	/* Look for the unit id info */	EXPECT(UnitId, 10);	SNARF(IDbuf, 2);	delim = IDbuf + strcspn(IDbuf, WHITESPACE);	*delim = EOS;	REPLSTR(bt->unitid, IDbuf);	/* Expect "username>" */	EXPECT(login, 2);	SEND(bt->user);	SEND("\r");	/* Expect "password>" */	switch (RPCLookFor(bt, password, 5)) {		case 0:	/* Good! */			break;		case 1:	/* OOPS!  got another username prompt */			syslog(LOG_ERR, _("Invalid username for " DEVICE "."));			return(S_ACCESS);		default:			return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	}	SEND(bt->passwd);	SEND("\r");	/* Expect "RPC-x Menu" */	switch (RPCLookFor(bt, LoginOK, 5)) {		case 0:	/* Good! */			break;		case 1:	/* Uh-oh - bad password */			syslog(LOG_ERR, _("Invalid password for " DEVICE "."));			return(S_ACCESS);		default:			RPCkillcomm(bt);			return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	}	EXPECT(Menu, 2);	return(S_OK);}static intRPCRobustLogin(struct BayTech * bt){	int	rc=S_OOPS;	int	j;	for (j=0; j < 20 && rc != S_OK; ++j) {		if (bt->pid > 0) {			RPCkillcomm(bt);		}		if (RPC_connect_device(bt) != S_OK) {			RPCkillcomm(bt);			continue;		}		rc = RPCLogin(bt);	}	return rc;}/* Log out of the Baytech RPC */static intRPCLogout(struct BayTech* bt){	int	rc;	/* Make sure we're in the right menu... */	SEND("\r");	/* Expect "Selection>" */	rc = RPCLookFor(bt, Selection, 5);	/* Option 6 is Logout */	SEND("6\r");	close(bt->wrfd);	close(bt->rdfd);	bt->wrfd = bt->rdfd = -1;	RPCkillcomm(bt);	return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));}static voidRPCkillcomm(struct BayTech* bt){	if (bt->pid > 0) {		STONITH_KILL(bt->pid, SIGKILL);		(void)waitpid(bt->pid, NULL, 0);		bt->pid = -1;	}}/* Reset (power-cycle) the given outlet number */static intRPCReset(struct BayTech* bt, int unitnum, const char * rebootid){	char		unum[32];	SEND("\r");	/* Make sure we're in the top level menu */	/* Expect "RPC-x Menu" */	EXPECT(RPC, 5);	EXPECT(Menu, 5);	/* OK.  Request sub-menu 1 (Outlet Control) */	SEND("1\r");	/* Verify that we're in the sub-menu */	/* Expect: "RPC-x>" */	EXPECT(RPC, 5);	EXPECT(GTSign, 5);	/* Send REBOOT command for given outlet */	snprintf(unum, sizeof(unum), "REBOOT %d\r", unitnum);	SEND(unum);	/* Expect "ebooting "... or "(Y/N)" (if confirmation turned on) */	retry:	switch (RPCLookFor(bt, Rebooting, 5)) {		case 0: /* Got "Rebooting" Do nothing */			break;		case 1: /* Got that annoying command confirmation :-( */			SEND("Y\r");			goto retry;		case 2:	/* Outlet is turned off */			syslog(LOG_ERR, _("Host %s is OFF."), rebootid);			return(S_ISOFF);		default:			return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}	syslog(LOG_INFO, _("Host %s being rebooted."), rebootid);	/* Expect "ower applied to outlet" */	if (RPCLookFor(bt, PowerApplied, 30) < 0) {		return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}	/* All Right!  Power is back on.  Life is Good! */	syslog(LOG_INFO, _("Power restored to host %s."), rebootid);	/* Expect: "RPC-x>" */	EXPECT(RPC,5);	EXPECT(GTSign, 5);	/* Pop back to main menu */	SEND("MENU\r");	return(S_OK);}#if defined(ST_POWERON) && defined(ST_POWEROFF)static intRPC_onoff(struct BayTech* 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)) {		syslog(LOG_ERR, _("Cannot log into " DEVICE "."));		return(rc);	}	SEND("\r");	/* Make sure we're in the top level menu */	/* Expect "RPC-x Menu" */	EXPECT(RPC, 5);	EXPECT(Menu, 5);	/* OK.  Request sub-menu 1 (Outlet Control) */	SEND("1\r");	/* Verify that we're in the sub-menu */	/* Expect: "RPC-x>" */	EXPECT(RPC, 5);	EXPECT(GTSign, 5);	/* Send ON/OFF command for given outlet */	snprintf(unum, sizeof(unum), "%s %d\r"	,	onoff, unitnum);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -