?? apcmaster.c
字號:
/* $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 + -