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

📄 wti_nps.c

📁 在LINUX下实现HA的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: wti_nps.c,v 1.10.2.3 2005/06/28 16:09:39 blaschke Exp $ *//* * *  Copyright 2001 Mission Critical Linux, Inc. * *  All Rights Reserved. *//* *	Stonith module for WTI Network Power Switch Devices (NPS-xxx) *	Also supports the WTI Telnet Power Switch Devices (TPS-xxx) * *  Copyright 2001 Mission Critical Linux, Inc. *  author: mike ledoux <mwl@mclinux.com> *  author: Todd Wheeling <wheeling@mclinux.com> * *  Based strongly on original code from baytech.c by Alan Robertson. * * 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 * *//*                          Observations/Notes *  * 1. The WTI Network Power Switch, unlike the BayTech network power switch, *    accpets only one (telnet) connection/session at a time. When one *    session is active, any subsequent attempt to connect to the NPS will *    result in a connection refused/closed failure. In a cluster environment *    or other environment utilizing polling/monitoring of the NPS *    (from multiple nodes), this can clearly cause problems. Obviously the *    more nodes and the shorter the polling interval, the more frequently such *    errors/collisions may occur. * * 2. We observed that on busy networks where there may be high occurances *    of broadcasts, the NPS became unresponsive.  In some  *    configurations this necessitated placing the power switch onto a  *    private subnet. */#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              wti_nps#define PIL_PLUGIN_S            "wti_nps"#define PIL_PLUGINLICENSE 	LICENSE_LGPL#define PIL_PLUGINLICENSEURL 	URL_LGPL#include <pils/plugin.h>#include "stonith_signal.h"/* * wti_npsclose is called as part of unloading the wti_nps 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 voidwti_npsclosepi(PILPlugin*pi){}/* * wti_npscloseintf called as part of shutting down the wti_nps STONITH * interface.  If there was any global data allocated, or file descriptors * opened, etc.  which is associated with the wti_nps implementation, * here's our chance to clean it up. */static PIL_rcwti_npscloseintf(PILInterface* pi, void* pd){	return PIL_OK;}static void *		wti_nps_new(void);static void		wti_nps_destroy(Stonith *);static int		wti_nps_set_config_file(Stonith *, const char * cfgname);static int		wti_nps_set_config_info(Stonith *, const char * info);static const char *	wti_nps_getinfo(Stonith * s, int InfoType);static int		wti_nps_status(Stonith * );static int		wti_nps_reset_req(Stonith * s, int request, const char * host);static char **		wti_nps_hostlist(Stonith  *);static void		wti_nps_free_hostlist(char **);static struct stonith_ops wti_npsOps ={	wti_nps_new,		/* Create new STONITH object	*/	wti_nps_destroy,		/* Destroy STONITH object	*/	wti_nps_set_config_file,	/* set configuration from file	*/	wti_nps_set_config_info,	/* Get configuration from file	*/	wti_nps_getinfo,		/* Return STONITH info string	*/	wti_nps_status,		/* Return STONITH device status	*/	wti_nps_reset_req,		/* Request a reset */	wti_nps_hostlist,		/* Return list of supported hosts */	wti_nps_free_hostlist	/* free above list */};PIL_PLUGIN_BOILERPLATE("1.0", Debug, wti_npsclosepi);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	,	&wti_npsOps	,	wti_npscloseintf		/*close */	,	&OurInterface	,	(void*)&OurImports	,	&interfprivate); }#define	DEVICE	"WTI Network Power Switch"#define N_(text)	(text)#define _(text)		dgettext(ST_TEXTDOMAIN, text)/* *	I have a NPS-110.  This code has been tested with this switch. *	(Tested with NPS-230 and TPS-2 by lmb) */struct WTINPS {	const char *	NPSid;	char *		idinfo;	char *		unitid;	pid_t		pid;	int		rdfd;	int		wrfd;	int		config;	char *		device;	char *		passwd;};static const char * NPSid = "WTINPS-Stonith";static const char * NOTnpsid = "Hey, dummy this has been destroyed (WTINPS)";#define	ISWTINPS(i)	(((i)!= NULL && (i)->pinfo != NULL)	\	&& ((struct WTINPS *)(i->pinfo))->NPSid == NPSid)#define	ISCONFIGED(i)	(ISWTINPS(i) && ((struct WTINPS *)(i->pinfo))->config)#ifndef MALLOC#	define	MALLOC	malloc#endif#ifndef FREE#	define	FREE	free#endif#ifndef MALLOCT#	define     MALLOCT(t)      ((t *)(MALLOC(sizeof(t)))) #endif#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 WTI *	Network Power Switch */#define WTINPSSTR	" Power Switch"#define WTINBBSTR	"Network Boot Bar"static struct Etoken EscapeChar[] =	{ {"Escape character is '^]'.", 0, 0}					,	{NULL,0,0}};static struct Etoken password[] =	{ {"Password:", 0, 0}					,	{NULL,0,0}};static struct Etoken Prompt[] =		{ {"PS>", 0, 0}					,	{"NBB>", 0, 0}					,	{NULL,0,0}};static struct Etoken LoginOK[] =	{ {WTINPSSTR, 0, 0}					,	{WTINBBSTR, 0, 0}					,	{"Invalid password", 1, 0}					,	{NULL,0,0}};static struct Etoken Separator[] =	{ {"-----+", 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 Processing[] =	{ {"rocessing - please wait", 0, 0}				,	{"(Y/N):", 1, 0}				,	{NULL,0,0}};static int	NPSLookFor(struct WTINPS* nps, struct Etoken * tlist, int timeout);static int	NPS_connect_device(struct WTINPS * nps);static int	NPSLogin(struct WTINPS * nps);static int	NPSNametoOutlet(struct WTINPS*, const char * name, char **outlets);static int	NPSReset(struct WTINPS*, char * outlets, const char * rebootid);static int	NPSScanLine(struct WTINPS* nps, int timeout, char * buf, int max);static int	NPSLogout(struct WTINPS * nps);static void	NPSkillcomm(struct WTINPS * nps);static int	NPS_parse_config_info(struct WTINPS* nps, const char * info);#if defined(ST_POWERON) && defined(ST_POWEROFF)static int	NPS_onoff(struct WTINPS*, const char * outlets, const char * unitid,		int request);#endif/* *	We do these things a lot.  Here are a few shorthand macros. */#define	SEND(s) (write(nps->wrfd, (s), strlen(s)))#define	EXPECT(p,t)	{						\			if (NPSLookFor(nps, p, t) < 0)			\				return(errno == ETIMEDOUT			\			?	S_TIMEOUT : S_OOPS);			\			}#define	NULLEXPECT(p,t)	{						\				if (NPSLookFor(nps, p, t) < 0)		\					return(NULL);			\			}#define	SNARF(s, to)	{						\				if (NPSScanLine(nps,to,(s),sizeof(s))	\				!=	S_OK)				\					return(S_OOPS);			\			}#define	NULLSNARF(s, to)	{					\				if (NPSScanLine(nps,to,(s),sizeof(s))	\				!=	S_OK)				\					return(NULL);			\				}/* Look for any of the given patterns.  We don't care which */static intNPSLookFor(struct WTINPS* nps, struct Etoken * tlist, int timeout){	int	rc;	if ((rc = EXPECT_TOK(nps->rdfd, tlist, timeout, NULL, 0)) < 0) {		syslog(LOG_ERR, _("Did not find string: '%s' from " DEVICE ".")		,	tlist[0].string);		NPSkillcomm(nps);	}	return(rc);}/* Read and return the rest of the line */static intNPSScanLine(struct WTINPS* nps, int timeout, char * buf, int max){	if (EXPECT_TOK(nps->rdfd, CRNL, timeout, buf, max) < 0) {		syslog(LOG_ERR, ("Could not read line from " DEVICE "."));		NPSkillcomm(nps);		return(S_OOPS);	}	return(S_OK);}/* Attempt to login up to 20 times... */static intNPSRobustLogin(struct WTINPS * nps){	int rc = S_OOPS;	int j = 0;	for ( ; ; ) {	  if (nps->pid > 0)	    NPSkillcomm(nps);	  if (NPS_connect_device(nps) != S_OK) {		      NPSkillcomm(nps);	  }	  else {	    rc = NPSLogin(nps);	    if (rc == S_OK) break;	  }	  if ((++j) == 20) break;	  else sleep(1);	}	return rc;}/* Login to the WTI Network Power Switch (NPS) */static intNPSLogin(struct WTINPS * nps){	char		IDinfo[128];	char *		idptr = IDinfo;	/*EXPECT(EscapeChar, 10);*/	if (NPSLookFor(nps, EscapeChar, 10) < 0) {		sleep(1);		return (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	}	/* Look for the unit type info */	if (EXPECT_TOK(nps->rdfd, password, 2, IDinfo	,	sizeof(IDinfo)) < 0) {		syslog(LOG_ERR, _("No initial response from " DEVICE "."));		NPSkillcomm(nps); 		return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	}	idptr += strspn(idptr, WHITESPACE);	/*	 * We should be looking at something like this:	 *	Enter Password: 	 */	SEND(nps->passwd);	SEND("\r");	/* Expect "Network Power Switch vX.YY" */	switch (NPSLookFor(nps, LoginOK, 5)) {		case 0:	/* Good! */			syslog(LOG_INFO, _("Successful login to " DEVICE "."));			break;		case 1:	/* Uh-oh - bad password */			syslog(LOG_ERR, _("Invalid password for " DEVICE "."));			return(S_ACCESS);		default:			NPSkillcomm(nps);			return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	}	return(S_OK);}/* Log out of the WTI NPS */static intNPSLogout(struct WTINPS* nps){	int	rc;	/* Send "/h" help command and expect back prompt */	/* SEND("/h\r"); */	/* Expect "PS>" */	rc = NPSLookFor(nps, Prompt, 5);	/* "/x" is Logout, "/x,y" auto-confirms */	SEND("/x,y\r");	NPSkillcomm(nps);	return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));}static voidNPSkillcomm(struct WTINPS* nps){        if (nps->rdfd >= 0) {	        close(nps->rdfd);	        nps->rdfd = -1;	}	if (nps->wrfd >= 0) {	        close(nps->wrfd);  	        nps->wrfd = -1;	}        if (nps->pid > 0) {	        STONITH_KILL(nps->pid, SIGKILL);				(void)waitpid(nps->pid, NULL, 0);		nps->pid = -1;	}}/* Reset (power-cycle) the given outlets */static intNPSReset(struct WTINPS* nps, char * outlets, const char * rebootid){	char		unum[32];	/* Send "/h" help command and expect back prompt */	SEND("/h\r");	/* Expect "PS>" */	EXPECT(Prompt, 5);		/* Send REBOOT command for given outlets */	snprintf(unum, sizeof(unum), "/BOOT %s,y\r", outlets);	SEND(unum);		/* Expect "Processing "... or "(Y/N)" (if confirmation turned on) */	retry:	switch (NPSLookFor(nps, Processing, 5)) {		case 0: /* Got "Processing" Do nothing */			break;		case 1: /* Got that annoying command confirmation :-( */			SEND("Y\r");			goto retry;		default: 			return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}	syslog(LOG_INFO, _("Host %s being rebooted."), rebootid);	/* Expect "PS>" */	if (NPSLookFor(nps, Prompt, 60) < 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);	SEND("/h\r");	return(S_OK);}#if defined(ST_POWERON) && defined(ST_POWEROFF)static intNPS_onoff(struct WTINPS* nps, const char * outlets, const char * unitid, int req){	char		unum[32];	const char *	onoff = (req == ST_POWERON ? "/On" : "/Off");	int	rc;	if ((rc = NPSRobustLogin(nps) != S_OK)) {		syslog(LOG_ERR, _("Cannot log into " DEVICE "."));		return(rc);	}       	/* Send "/h" help command and expect prompt back */	SEND("/h\r");	/* Expect "PS>" */	EXPECT(Prompt, 5);	/* Send ON/OFF command for given outlet */	snprintf(unum, sizeof(unum), "%s %s,y\r", onoff, outlets);	SEND(unum);	/* Expect "Processing"... or "(Y/N)" (if confirmation turned on) */	if (NPSLookFor(nps, Processing, 5) == 1) {		/* They've turned on that annoying command confirmation :-( */		SEND("Y\r");	}	EXPECT(Prompt, 60);	/* All Right!  Command done. Life is Good! */	syslog(LOG_NOTICE, _("Power to NPS outlet(s) %s turned %s."), outlets, onoff);	return(S_OK);}#endif /* defined(ST_POWERON) && defined(ST_POWEROFF) *//*

⌨️ 快捷键说明

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