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

📄 apcsmart.c

📁 在LINUX下实现HA的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: apcsmart.c,v 1.12.2.4 2005/04/22 13:53:26 blaschke Exp $ *//* * Stonith module for APCSmart Stonith device * Copyright (c) 2000 Andreas Piesk <a.piesk@gmx.net> * 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 * * UPS code is taken from: *   'Network UPS Tools' by Russell Kroll <rkroll@exploits.org> *   homepage: http://www.exploits.org/nut/ */#include <portability.h>#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <syslog.h>#include <libintl.h>#include <fcntl.h>#include <termios.h>#include <sys/wait.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <stonith/stonith.h>#include <glib.h>/* * APCSmart (tested with old 900XLI, APC SmartUPS 700 and SmartUPS-1000) * * The reset is a combined reset: "S" and "@000" * The "S" command tells the ups that if it is on-battery, it should * remain offline until the power is back.  * If that command is not accepted, the "@000" command will be sent * to tell the ups to turn off and back on right away. * In both cases, if the UPS supports a 20 second shutdown grace * period (such as on the 900XLI), the shutdown will delay that long, * otherwise the shutdown will happen immediately (the code searches * for the smallest possible delay). */#define	DEVICE	                "APCSmart-Stonith"#define CFG_FILE		"/etc/ha.d/apcsmart.cfg"#define MAX_DEVICES		1#define SERIAL_TIMEOUT		3	/* timeout in sec */#define SEND_DELAY		50000	/* in 祍 */#define ENDCHAR			10	/* use LF */#define MAX_STRING              512#define MAX_DELAY_STRING	16#define SWITCH_TO_NEXT_VAL	"-"	/* APC cmd for cycling through					 * the values					 */#define CMD_SMART_MODE          "Y"#define RSP_SMART_MODE		"SM"#define CMD_GET_STATUS		"Q"#define RSP_GET_STATUS		NULL#define CMD_RESET               "S"	/* turn off & stay off if on battery */#define CMD_RESET2              "@000"	/* turn off & immediately turn on */#define RSP_RESET		"*"	/* RESET response from older models */#define RSP_RESET2		"OK"	/* RESET response from newer models */#define CMD_SHUTDOWN_DELAY	"p"#define CMD_WAKEUP_DELAY	"r"#define CR			13struct APCDevice {    const char *APCid;		/* of object				*/    char **hostlist;		/* served by the device (only 1)	*/    int hostcount;		/* of hosts (1)				*/    char *upsdev;		/*					*/    int upsfd;			/* for serial port			*/    char shutdown_delay[MAX_DELAY_STRING]; /* smallest shutdown delay   */    char old_shutdown_delay[MAX_DELAY_STRING]; /* old shutdown delay	*/    char wakeup_delay[MAX_DELAY_STRING]; /* smallest wakeup delay	*/    char old_wakeup_delay[MAX_DELAY_STRING]; /* old wakeup delay	*/};/* saving old settings */static struct termios old_tio;static int f_serialtimeout;	/* flag for timeout */static const char *APCid = DEVICE;static const char *NOTapcID = "destroyed (APCSmart)";#define	ISAPCDEV(i) (((i)!= NULL && (i)->pinfo != NULL)	&& \                    ((struct APCDevice *)(i->pinfo))->APCid == APCid)#define ISCONFIGED(i) (((struct APCDevice *)(i->pinfo))->upsdev != NULL)#define _(text) dgettext(ST_TEXTDOMAIN, text)/* * stonith prototypes  */#define PIL_PLUGINTYPE          STONITH_TYPE#define PIL_PLUGINTYPE_S        STONITH_TYPE_S#define PIL_PLUGIN              apcsmart#define PIL_PLUGIN_S            "apcsmart"#define PIL_PLUGINLICENSE 	LICENSE_LGPL#define PIL_PLUGINLICENSEURL 	URL_LGPL#include <pils/plugin.h>#include "stonith_signal.h"/* * apcsmartclose is called as part of unloading the apcsmart 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 voidapcsmartclosepi(PILPlugin*pi){}/* * apcsmartcloseintf called as part of shutting down the apcsmart STONITH * interface.  If there was any global data allocated, or file descriptors * opened, etc.  which is associated with the apcsmart implementation, * here's our chance to clean it up. */static PIL_rcapcsmartcloseintf(PILInterface* pi, void* pd){	return PIL_OK;}static void *		apcsmart_new(void);static void		apcsmart_destroy(Stonith *);static int		apcsmart_set_config_file(Stonith *, const char * cfgname);static int		apcsmart_set_config_info(Stonith *, const char * info);static const char *	apcsmart_getinfo(Stonith * s, int InfoType);static int		apcsmart_status(Stonith * );static int		apcsmart_reset_req(Stonith * s, int request, const char * host);static char **		apcsmart_hostlist(Stonith  *);static void		apcsmart_free_hostlist(char **);static struct stonith_ops apcsmartOps ={	apcsmart_new,		/* Create new STONITH object	*/	apcsmart_destroy,		/* Destroy STONITH object	*/	apcsmart_set_config_file,	/* set configuration from file	*/	apcsmart_set_config_info,	/* Get configuration from file	*/	apcsmart_getinfo,		/* Return STONITH info string	*/	apcsmart_status,		/* Return STONITH device status	*/	apcsmart_reset_req,		/* Request a reset */	apcsmart_hostlist,		/* Return list of supported hosts */	apcsmart_free_hostlist		/* free above list */};PIL_PLUGIN_BOILERPLATE("1.0", Debug, apcsmartclosepi);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->StartProcess#undef MALLOCT#define MALLOCT(t) ((t *)(MALLOC(sizeof(t))))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	,	&apcsmartOps	,	apcsmartcloseintf		/*close */	,	&OurInterface	,	(void*)&OurImports	,	&interfprivate); }/* * own prototypes  */int APC_open_serialport(const char *port, speed_t speed);void APC_close_serialport(int upsfd);void APC_sh_serial_timeout(int sig);int APC_send_cmd(int upsfd, const char *cmd);int APC_recv_rsp(int upsfd, char *rsp);int APC_enter_smartmode(int upsfd);int APC_set_ups_var(int upsfd, const char *cmd, char *newval);int APC_get_smallest_delay(int upsfd, const char *cmd, char *smdelay);int APC_parse_config_info(struct APCDevice *ad, const char *info );int APC_init( struct APCDevice *ad );void APC_deinit( struct APCDevice *ad );/* * * Portable locking (non-blocking) * * This is a candidate for including in a general portability library. */static intfile_lock(int fd){	int ret;#ifdef HAVE_FCNTL	struct flock l;	l.l_type = F_WRLCK;	l.l_whence = 0;	l.l_start = 0;	l.l_len = 0;	ret = fcntl(fd, F_SETLK, &l);	return((ret == -1) ? -1 : 0);#else#  ifdef HAVE_FLOCK	ret = flock(fd, LOCK_EX | LOCK_NB);	return(ret);#  else#    error "No locking method (flock, fcntl) is available"	return(-1);#  endif /* HAVE_FLOCK */#endif /* HAVE_FCNTL */}static intfile_unlock(int fd){	int ret;#ifdef HAVE_FCNTL	struct flock l;	l.l_type = F_UNLCK;	l.l_whence = 0;	l.l_start = 0;	l.l_len = 0;	ret = fcntl(fd, F_SETLK, &l);	return((ret == -1) ? -1 : 0);#else#  ifdef HAVE_FLOCK	ret = flock(fd, LOCK_UN);	return(ret);#  else#    error "No unlocking method (flock, fcntl) is available"	return(-1);#  endif /* HAVE_FLOCK */#endif /* HAVE_FCNTL */}/* * Signal handler for serial port timeouts  */voidAPC_sh_serial_timeout(int sig){#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    STONITH_IGNORE_SIG(SIGALRM);#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: serial port timed out.", __FUNCTION__);#endif    f_serialtimeout = TRUE;    return;}/* * Open serial port and set it to b2400  */intAPC_open_serialport(const char *port, speed_t speed){    struct termios tio;    int fd;#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    STONITH_SIGNAL(SIGALRM, APC_sh_serial_timeout);    alarm(SERIAL_TIMEOUT);    f_serialtimeout = FALSE;    fd = open(port, O_RDWR | O_NOCTTY | O_NONBLOCK | O_EXCL);    alarm(0);    STONITH_IGNORE_SIG(SIGALRM);    if (fd < 0) {#ifdef APC_DEBUG	syslog(LOG_DEBUG, "%s: 1st open failed.", __FUNCTION__);#endif	return -1;    }    if (file_lock(fd) != 0) {#ifdef APC_DEBUG	syslog(LOG_DEBUG, "%s: 1st lock failed.", __FUNCTION__);#endif	close(fd);	return -1;    }    tcgetattr(fd, &old_tio);    memcpy(&tio, &old_tio, sizeof(struct termios));    tio.c_lflag = 0 | ECHOE | ECHOKE | ECHOCTL | PENDIN;    tio.c_iflag = 0 | IXANY | IMAXBEL | IXOFF;    tio.c_oflag = 0 | ONLCR;    tio.c_cflag = 0 | CREAD | CS8 | HUPCL | CLOCAL;    cfsetispeed(&tio, speed);    cfsetospeed(&tio, speed);    tio.c_cc[VMIN] = 1;    tio.c_cc[VTIME] = 0;    tcflush(fd, TCIFLUSH);    tcsetattr(fd, TCSANOW, &tio);    close(fd);    STONITH_SIGNAL(SIGALRM, APC_sh_serial_timeout);    alarm(SERIAL_TIMEOUT);    fd = open(port, O_RDWR | O_NOCTTY | O_EXCL);    alarm(0);    STONITH_IGNORE_SIG(SIGALRM);    if (fd < 0) {#ifdef APC_DEBUG	syslog(LOG_DEBUG, "%s: 2nd open failed.", __FUNCTION__);#endif	return -1;    }    if (file_lock(fd) != 0) {#ifdef APC_DEBUG	syslog(LOG_DEBUG, "%s: 2nd lock failed.", __FUNCTION__);#endif	close(fd);	return -1;    }    tcgetattr(fd, &tio);    tio.c_cflag = CS8 | CLOCAL | CREAD;    tio.c_iflag = IGNPAR;    tio.c_oflag = 0;    tio.c_lflag = 0;    tio.c_cc[VMIN] = 1;    tio.c_cc[VTIME] = 0;    cfsetispeed(&tio, speed);    cfsetospeed(&tio, speed);    tcflush(fd, TCIFLUSH);    tcsetattr(fd, TCSANOW, &tio);    return (fd);}/* * Close serial port and restore old settings  */voidAPC_close_serialport(int upsfd){#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    file_unlock(upsfd);    tcflush(upsfd, TCIFLUSH);    tcsetattr(upsfd, TCSANOW, &old_tio);    close(upsfd);}/* * Send a command to the ups  */intAPC_send_cmd(int upsfd, const char *cmd){    int i;#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    for (i = strlen(cmd); i > 0; i--) {	tcflush(upsfd, TCIFLUSH);	if (write(upsfd, cmd++, 1) != 1)	    return (S_ACCESS);	usleep(SEND_DELAY);    }    return (S_OK);}/* * Get the response from the ups  */intAPC_recv_rsp(int upsfd, char *rsp){    char *p = rsp;    char inp;    int num = 0;#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    *p = '\0';    STONITH_SIGNAL(SIGALRM, APC_sh_serial_timeout);    alarm(SERIAL_TIMEOUT);    while (num < MAX_STRING) {	if (read(upsfd, &inp, 1) == 1) {	    /* shutdown sends only a '*' without LF  */	    if ((inp == '*') && (num == 0)) {		*p++ = inp;		num++;		inp = ENDCHAR;	    }	    if (inp == ENDCHAR) {		alarm(0);		STONITH_IGNORE_SIG(SIGALRM);		*p = '\0';		return (S_OK);	    }	    if (inp != CR) {		*p++ = inp;		num++;	    }	} else {	    alarm(0);	    STONITH_IGNORE_SIG(SIGALRM);	    *p = '\0';	    return (f_serialtimeout ? S_TIMEOUT : S_ACCESS);	}    }    return (S_ACCESS);}/* *  Enter smart mode */intAPC_enter_smartmode(int upsfd){    int rc;    char resp[MAX_STRING];#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    strcpy( resp, RSP_SMART_MODE);    if (((rc = APC_send_cmd(upsfd, CMD_SMART_MODE)) == S_OK) &&	((rc = APC_recv_rsp(upsfd, resp)) == S_OK) &&	(strcmp(RSP_SMART_MODE, resp) == 0))	return (S_OK);    return (S_ACCESS);}/*  * Set a value in the hardware using the <cmdchar> '-' (repeat) approach */intAPC_set_ups_var(int upsfd, const char *cmd, char *newval){    char resp[MAX_STRING];    char orig[MAX_STRING];    int rc;#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: called.", __FUNCTION__);#endif    if (((rc = APC_enter_smartmode(upsfd)) != S_OK) ||	((rc = APC_send_cmd(upsfd, cmd)) != S_OK) ||	((rc = APC_recv_rsp(upsfd, orig)) != S_OK))	return (rc);#ifdef APC_DEBUG    syslog(LOG_DEBUG, "%s: var '%s' original val %s", __FUNCTION__, cmd, orig);#endif    if (strcmp(orig, newval) == 0)	return (S_OK);		/* already set */    *resp = '\0';    while (strcmp(resp, orig) != 0) {	if (((rc = APC_send_cmd(upsfd, SWITCH_TO_NEXT_VAL)) != S_OK) ||	    ((rc = APC_recv_rsp(upsfd, resp)) != S_OK))	    return (rc);	if (((rc = APC_enter_smartmode(upsfd)) != S_OK) ||	    ((rc = APC_send_cmd(upsfd, cmd)) != S_OK) ||	    ((rc = APC_recv_rsp(upsfd, resp)) != S_OK))	    return (rc);	if (strcmp(resp, newval) == 0) {#ifdef APC_DEBUG	    syslog(LOG_DEBUG, "%s: var '%s' set to %s", __FUNCTION__, 		    						cmd, newval);#endif	    strcpy(newval, orig);	/* return the old value */	    return (S_OK);		/* got it */	}    }    syslog(LOG_ERR, "%s(): variable '%s' wrapped!", __FUNCTION__, cmd);    syslog(LOG_ERR, "%s(): This UPS may not support STONITH :-("    ,	 __FUNCTION__);    return (S_OOPS);}/*  * Query the smallest delay supported by the hardware using the  * <cmdchar> '-' (repeat) approach and looping through all possible values, * saving the smallest */

⌨️ 快捷键说明

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