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

📄 apcmaster.c

📁 linux集群服务器软件代码包
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: apcmaster.c,v 1.19 2005/02/17 09:20:18 sunjd Exp $ *//***  Copyright 2001 Mission Critical Linux, Inc.**  All Rights Reserved.*//* *	Stonith module for APC Master Switch (AP9211) * *  Copyright (c) 2001 Mission Critical Linux, Inc. *  author: mike ledoux <mwl@mclinux.com> *  author: Todd Wheeling <wheeling@mclinux.com> *  mangled by Sun Jiang Dong, <sunjd@cn.ibm.com>, IBM, 2005 * *  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 APC MasterSwitch, unlike the BayTech network power switch, *    accepts only one (telnet) connection/session at a time. When one *    session is active, any subsequent attempt to connect to the MasterSwitch  *    will result in a connection refused/closed failure. In a cluster  *    environment or other environment utilizing polling/monitoring of the  *    MasterSwitch (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 MasterSwitch became unresponsive.  In some  *    configurations this necessitated placing the power switch onto a  *    private subnet. *//* * Version string that is filled in by CVS */static const char *version __attribute__ ((unused)) = "$Revision: 1.19 $"; #define	DEVICE	"APC MasterSwitch"#include "stonith_plugin_common.h"#define PIL_PLUGIN              apcmaster#define PIL_PLUGIN_S            "apcmaster"#define PIL_PLUGINLICENSE 	LICENSE_LGPL#define PIL_PLUGINLICENSEURL 	URL_LGPL#include <pils/plugin.h>#include "stonith_signal.h"static StonithPlugin *	apcmaster_new(void);static void		apcmaster_destroy(StonithPlugin *);static const char **	apcmaster_get_confignames(StonithPlugin *);static int		apcmaster_set_config(StonithPlugin *, StonithNVpair *);static const char *	apcmaster_getinfo(StonithPlugin * s, int InfoType);static int		apcmaster_status(StonithPlugin * );static int		apcmaster_reset_req(StonithPlugin * s, int request, const char * host);static char **		apcmaster_hostlist(StonithPlugin  *);static struct stonith_ops apcmasterOps ={	apcmaster_new,		/* Create new STONITH object	*/	apcmaster_destroy,		/* Destroy STONITH object	*/	apcmaster_getinfo,		/* Return STONITH info string	*/	apcmaster_get_confignames,	/* Get configuration parameters */	apcmaster_set_config,		/* Set configuration */	apcmaster_status,		/* Return STONITH device status	*/	apcmaster_reset_req,		/* Request a reset */	apcmaster_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_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	,	&apcmasterOps	,	NULL		/*close */	,	&OurInterface	,	(void*)&OurImports	,	&interfprivate); }/* *	I have an AP9211.  This code has been tested with this switch. */struct pluginDevice {	StonithPlugin	sp;	const char *	pluginid;	char *		idinfo;	char *		unitid;	pid_t		pid;	int		rdfd;	int		wrfd;	int		config;	char *		device;        char *		user;	char *		passwd;};static const char * pluginid = "APCMS-Stonith";static const char * NOTpluginID = "Hey dummy, this has been destroyed (APCMS)";/* *	Different expect strings that we get from the APC MasterSwitch */#define APCMSSTR	"American Power Conversion"static struct Etoken EscapeChar[] =	{ {"Escape character is '^]'.", 0, 0}					,	{NULL,0,0}};static struct Etoken login[] = 		{ {"User Name :", 0, 0}, {NULL,0,0}};static struct Etoken password[] =	{ {"Password  :", 0, 0} ,{NULL,0,0}};static struct Etoken Prompt[] =	{ {"> ", 0, 0} ,{NULL,0,0}};static struct Etoken LoginOK[] =	{ {APCMSSTR, 0, 0}                    , {"User Name :", 1, 0} ,{NULL,0,0}};static struct Etoken Separator[] =	{ {"-----", 0, 0} ,{NULL,0,0}};/* We may get a notice about rebooting, or a request for confirmation */static struct Etoken Processing[] =	{ {"Press <ENTER> to continue", 0, 0}				,	{"Enter 'YES' to continue", 1, 0}				,	{NULL,0,0}};static int	MS_connect_device(struct pluginDevice * ms);static int	MSLogin(struct pluginDevice * ms);static int	MSRobustLogin(struct pluginDevice * ms);static int	MSNametoOutlet(struct pluginDevice*, const char * name);static int	MSReset(struct pluginDevice*, int outletNum, const char * host);static int	MSLogout(struct pluginDevice * ms);#if defined(ST_POWERON) && defined(ST_POWEROFF)static int	apcmaster_onoff(struct pluginDevice*, int outletnum, const char * unitid,		int request);#endif/* Login to the APC Master Switch */static intMSLogin(struct pluginDevice * ms){        EXPECT(ms->rdfd, EscapeChar, 10);  	/* 	 * We should be looking at something like this:         *	User Name :	 */	EXPECT(ms->rdfd, login, 10);	SEND(ms->wrfd, ms->user);       	SEND(ms->wrfd, "\r");	/* Expect "Password  :" */	EXPECT(ms->rdfd, password, 10);	SEND(ms->wrfd, ms->passwd);	SEND(ms->wrfd, "\r"); 	switch (StonithLookFor(ms->rdfd, LoginOK, 30)) {		case 0:	/* Good! */			LOG(PIL_INFO, "%s", _("Successful login to " DEVICE ".")); 			break;		case 1:	/* Uh-oh - bad password */			LOG(PIL_CRIT,"%s", _("Invalid password for " DEVICE "."));			return(S_ACCESS);		default:			Stonithkillcomm(&ms->rdfd,&ms->wrfd,&ms->pid);			return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);	} 	return(S_OK);}/* Attempt to login up to 20 times... */static intMSRobustLogin(struct pluginDevice * ms){	int rc = S_OOPS;	int j = 0;	for ( ; ; ) {	  if (ms->pid > 0) {		Stonithkillcomm(&ms->rdfd,&ms->wrfd,&ms->pid);	  }	  if (MS_connect_device(ms) != S_OK) {			Stonithkillcomm(&ms->rdfd,&ms->wrfd,&ms->pid);	  } else {		rc = MSLogin(ms);		if( rc == S_OK ) {			break;	    	}	  }	  if ((++j) == 20) {		break;	  } else {		sleep(1);	  }	}	return rc;}/* Log out of the APC Master Switch */static int MSLogout(struct pluginDevice* ms){	int	rc;	/* Make sure we're in the right menu... */ 	/*SEND(ms->wrfd, "\033\033\033\033\033\033\033"); */        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "\033");		/* Expect "> " */	rc = StonithLookFor(ms->rdfd, Prompt, 5);	/* "4" is logout */	SEND(ms->wrfd, "4\r");	Stonithkillcomm(&ms->rdfd,&ms->wrfd,&ms->pid);	return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));}/* Reset (power-cycle) the given outlets */static intMSReset(struct pluginDevice* ms, int outletNum, const char *host){  	char		unum[32];	/* Make sure we're in the top level menu */        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "\033");		/* Expect ">" */	EXPECT(ms->rdfd, Prompt, 5);	/* Request menu 1 (Device Control) */	SEND(ms->wrfd, "1\r");	/* Select requested outlet */	EXPECT(ms->rdfd, Prompt, 5);	snprintf(unum, sizeof(unum), "%i\r", outletNum);  	SEND(ms->wrfd, unum);	/* Select menu 1 (Control Outlet) */	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "1\r");	/* Select menu 3 (Immediate Reboot) */	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "3\r");	/* Expect "Press <ENTER> " or "Enter 'YES'" (if confirmation turned on) */	retry:	switch (StonithLookFor(ms->rdfd, Processing, 5)) {		case 0: /* Got "Press <ENTER>" Do so */			SEND(ms->wrfd, "\r");			break;		case 1: /* Got that annoying command confirmation :-( */			SEND(ms->wrfd, "YES\r");			goto retry;		default: 			return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}		LOG(PIL_INFO, "%s: %s", _("Host being rebooted"), host); 	/* Expect ">" */	if (StonithLookFor(ms->rdfd, Prompt, 10) < 0) {		return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}	/* All Right!  Power is back on.  Life is Good! */	LOG(PIL_INFO, "%s: %s", _("Power restored to host"), host);	/* Return to top level menu */	SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "\033");	return(S_OK);}#if defined(ST_POWERON) && defined(ST_POWEROFF)static intapcmaster_onoff(struct pluginDevice* ms, int outletNum, const char * unitid, int req){	char		unum[32];	const char *	onoff = (req == ST_POWERON ? "1\r" : "2\r");	int	rc;	if ((rc = MSRobustLogin(ms) != S_OK)) {		LOG(PIL_CRIT, "%s", _("Cannot log into " DEVICE "."));		return(rc);	}		/* Make sure we're in the top level menu */        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);        SEND(ms->wrfd, "\033");	EXPECT(ms->rdfd, Prompt, 5);	SEND(ms->wrfd, "\033");	/* Expect ">" */	EXPECT(ms->rdfd, Prompt, 5);	/* Request menu 1 (Device Control) */	SEND(ms->wrfd, "1\r");	/* Select requested outlet */  	snprintf(unum, sizeof(unum), "%d\r", outletNum);   	SEND(ms->wrfd, unum); 	/* Select menu 1 (Control Outlet) */	SEND(ms->wrfd, "1\r");	/* Send ON/OFF command for given outlet */	SEND(ms->wrfd, onoff);	/* Expect "Press <ENTER> " or "Enter 'YES'" (if confirmation turned on) */	retry:	switch (StonithLookFor(ms->rdfd, Processing, 5)) {		case 0: /* Got "Press <ENTER>" Do so */			SEND(ms->wrfd, "\r");			break;		case 1: /* Got that annoying command confirmation :-( */			SEND(ms->wrfd, "YES\r");			goto retry;		default: 			return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);	}		EXPECT(ms->rdfd, Prompt, 10);

⌨️ 快捷键说明

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