Page Menu
Home
ClusterLabs Projects
Search
Configure Global Search
Log In
Files
F3152410
ipmilan.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
28 KB
Referenced Files
None
Subscribers
None
ipmilan.c
View Options
/** @file
* clumanager 1.2.x linux-cluster fence and/or GFS fence
* module for Intel/Bull/Dell Tiger4 machines via IPMI over lan.
* (Probably works with anything ipmitool can control, though.)
*
* Note: REQUIRES ipmitool to operate. On certain machines, the hardware
* manufacturer provides this tool for you. Otherwise, check:
*
* http://ipmitool.sourceforge.net
*
*/
#include "clusterautoconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <libintl.h>
/* fenced doesn't use the remote calls */
#define ST_STATUS 0
#define ST_POWERON 1
#define ST_POWEROFF 2
#define ST_GENERIC_RESET 3
#define ST_CYCLE 4
#define ST_DIAG 5
#define DEFAULT_TIMEOUT 20
#define DEFAULT_POWER_WAIT 2
#define DEFAULT_METHOD "onoff"
/* We should follow FenceAgentsAPI standard*/
#define ERR_OFF_SUCCESSFUL 0
#define ERR_OFF_FAIL 1
#define ERR_ON_SUCCESSFUL 0
#define ERR_ON_FAIL 1
#define ERR_STATUS_ON 0
#define ERR_STATUS_FAIL 1
#define ERR_STATUS_OFF 2
#define ERR_OK 0
#define log(lvl, fmt, args...) fprintf(stderr, fmt, ##args)
#include <libgen.h>
#include "copyright.cf"
#include "expect.h"
#define IPMIID "IPMI over LAN driver"
#define NOTIPMI "Destroyed IPMI over LAN driver"
#define dbg_printf(i, lvl, fmt, args...) \
do { \
if ( (i)->i_verbose >= lvl) { \
printf(fmt, ##args); \
fflush(stdout); \
} \
} while (0)
struct ipmi {
const char *i_id;
const char *i_ipmitool;
char *i_host;
char *i_user;
char *i_authtype;
char *i_password;
int i_rdfd;
int i_wrfd;
pid_t i_pid;
int i_config;
int i_verbose;
int i_lanplus;
int i_timeout;
int i_power_wait;
int i_cipher;
};
/*
Supported installation paths
*/
const char *ipmitool_paths[] = {
"/usr/local/bull/NSMasterHW/bin/ipmitool",
"/usr/bin/ipmitool",
"/usr/sbin/ipmitool",
"/bin/ipmitool",
"/sbin/ipmitool",
"/usr/local/bin/ipmitool",
"/usr/local/sbin/ipmitool",
NULL
};
#define ECIPHER 2048
#define ESTATE (8192*2)
static struct Etoken power_on_complete[] = {
{"Password:", EPERM, 0},
{"Unable to establish LAN", EAGAIN, 0}, /* Retry */
{"IPMI mutex", EFAULT, 0}, /* Death */
{"Unsupported cipher suite ID", ECIPHER,0},
{"read_rakp2_message: no support for", ECIPHER,0},
{"Up/On", 0, 0},
{NULL, 0, 0}
};
static struct Etoken power_off_complete[] = {
{"Password:", EPERM, 0},
{"Unable to establish LAN", EAGAIN, 0}, /* Retry */
{"IPMI mutex", EFAULT, 0}, /* Death */
{"Unsupported cipher suite ID", ECIPHER,0},
{"read_rakp2_message: no support for", ECIPHER,0},
{"Down/Off", 0, 0},
{NULL, 0, 0}
};
/** Powercycle operation */
static struct Etoken power_cycle_complete[] = {
{"Password:", EPERM, 0},
{"Unable to establish LAN", EAGAIN, 0}, /* Retry */
{"IPMI mutex", EFAULT, 0}, /* Death */
{"Unsupported cipher suite ID", ECIPHER,0},
{"read_rakp2_message: no support for", ECIPHER,0},
{"Command not supported in present state", ESTATE, 0},
{": Cycle", 0, 0},
{NULL, 0, 0}
};
#define STATE_OFF 4096
#define STATE_ON 8192
static struct Etoken power_status[] = {
{"Password:", EPERM, 0},
{"Unable to establish LAN", EAGAIN, 0}, /* Retry */
{"IPMI mutex", EFAULT, 0}, /* Death */
{"Unsupported cipher suite ID", ECIPHER,0},
{"read_rakp2_message: no support for", ECIPHER,0},
{"Chassis Power is off", STATE_OFF, 0},
{"Chassis Power is on", STATE_ON, 0},
{NULL, 0, 0}
};
/* Structure describing one xml metadata value*/
struct xml_parameter_s {
const char *name;
const char *getopt;
const int required;
const char *content_type;
const char *default_value;
const char *description;
};
/* Array of xml metadatas*/
struct xml_parameter_s xml_parameters[]={
{"auth","-A",0,"string",NULL,"IPMI Lan Auth type (md5, password, or none)"},
{"ipaddr","-a",1,"string",NULL,"IPMI Lan IP to talk to"},
{"passwd","-p",0,"string",NULL,"Password (if required) to control power on IPMI device"},
{"passwd_script","-S",0,"string",NULL,"Script to retrieve password (if required)"},
{"lanplus","-P",0,"boolean",NULL,"Use Lanplus"},
{"login","-l",0,"string",NULL,"Username/Login (if required) to control power on IPMI device"},
{"action","-o",0,"string","reboot","Operation to perform. Valid operations: on, off, reboot, status, list, diag, monitor or metadata"},
{"timeout","-t",0,"string",NULL,"Timeout (sec) for IPMI operation"},
{"cipher","-C",0,"string",NULL,"Ciphersuite to use (same as ipmitool -C parameter)"},
{"method","-M",0,"string",DEFAULT_METHOD,"Method to fence (onoff or cycle)"},
{"power_wait","-T",0,"string","2","Wait X seconds after on/off operation"},
{"delay","-f",0,"string",NULL,"Wait X seconds before fencing is started"},
{"verbose","-v",0,"boolean",NULL,"Verbose mode"}};
/*
Search for ipmitool
*/
static const char *
ipmitool_path(void)
{
char *p;
int x = 0;
struct stat sb;
for (x = 0; ipmitool_paths[x]; x++) {
p = (char *)ipmitool_paths[x];
if (stat(p, &sb) != 0)
continue;
if (!S_ISREG(sb.st_mode))
continue;
/* executable? */
if ((sb.st_mode & S_IXUSR) == 0)
continue;
return (const char *)p;
}
return NULL;
}
/** Prepare string for use in sh style environment. This function take source
string and prepend/append quote (') to start/end of source string to dest
string. Any occurence of quote in source string is replaced by '\'' sequence.
Dest string must be preallocated.
@param dest Destination string
@param source Source string
@param max_len Maximum length of data written to dest string (including end 0)
@return Pointer to start of destination string.
*/
static char *str_prepare_for_sh(char *dest,char *source,int max_len) {
char *dest_p=dest;
char *max_dest=dest+max_len;
if (dest_p+1>=max_dest) {*dest_p=0;return dest;}
*dest_p++='\'';
while (*source) {
if (*source=='\'') {
if (dest_p+4>=max_dest) {*dest_p=0;return dest;}
memcpy(dest_p,"'\\''",4);dest_p+=4;
} else {
if (dest_p+1>=max_dest) {*dest_p=0;return dest;}
*dest_p++=*source;
}
source++;
}
if (dest_p+2>=max_dest) {*dest_p=0;return dest;}
*dest_p++='\'';*dest_p=0;
return dest;
}
static int
build_cmd(char *command, size_t cmdlen, struct ipmi *ipmi, int op)
{
char cmd[2048];
char arg[2048];
char tmp[2048];
int x;
/* Store path */
if (ipmi->i_lanplus) {
snprintf(cmd, sizeof(cmd), "%s -I lanplus -H %s",
ipmi->i_ipmitool,
str_prepare_for_sh(tmp,ipmi->i_host,sizeof(tmp)));
} else {
snprintf(cmd, sizeof(cmd), "%s -I lan -H %s", ipmi->i_ipmitool,
str_prepare_for_sh(tmp,ipmi->i_host,sizeof(tmp)));
}
if (ipmi->i_user) {
snprintf(arg, sizeof(arg), " -U %s", str_prepare_for_sh(tmp,ipmi->i_user,sizeof(tmp)));
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
if (ipmi->i_authtype) {
snprintf(arg, sizeof(arg), " -A %s", str_prepare_for_sh(tmp,ipmi->i_authtype,sizeof(tmp)));
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
if (ipmi->i_cipher>=0) {
snprintf(arg, sizeof(arg), " -C %d", ipmi->i_cipher);
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
if (ipmi->i_password) {
snprintf(arg, sizeof(arg), " -P %s", str_prepare_for_sh(tmp,ipmi->i_password,sizeof(tmp)));
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
} else {
snprintf(arg, sizeof(arg), " -P ''");
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
/* Tack on the -v flags for ipmitool; in most cases, i_verbose
will be 0 */
for (x = 0; x < ipmi->i_verbose; x++) {
snprintf(arg, sizeof(arg), " -v");
strncat(cmd, arg, sizeof(cmd) - strlen(arg));
}
switch(op) {
case ST_POWERON:
snprintf(arg, sizeof(arg),
"%s chassis power on", cmd);
break;
case ST_POWEROFF:
snprintf(arg, sizeof(arg),
"%s chassis power off", cmd);
break;
case ST_STATUS:
snprintf(arg, sizeof(arg),
"%s chassis power status", cmd);
break;
case ST_CYCLE:
snprintf(arg, sizeof(arg),
"%s chassis power cycle", cmd);
break;
case ST_DIAG:
snprintf(arg, sizeof(arg),
"%s chassis power diag", cmd);
break;
}
strncpy(command, arg, cmdlen);
return 0;
}
static int
ipmi_spawn(struct ipmi *ipmi, const char *cmd)
{
dbg_printf(ipmi, 1, "Spawning: '%s'...\n", cmd);
if (!ipmi) {
errno = EINVAL;
return -1;
}
if (ipmi->i_pid != -1) {
dbg_printf(ipmi, 1, "Can't spawn: PID %d running\n",
(int)ipmi->i_pid);
errno = EINPROGRESS;
return -1;
}
if ((ipmi->i_pid = StartProcess(cmd, &ipmi->i_rdfd,
&ipmi->i_wrfd,
EXP_STDERR|EXP_NOCTTY)) >= 0) {
dbg_printf(ipmi, 2, "Spawned: '%s' - PID %d\n", cmd,
(int)ipmi->i_pid);
return 0;
}
return -1;
}
static int
ipmi_reap(struct ipmi *ipmi)
{
if (ipmi->i_pid >= 0) {
dbg_printf(ipmi, 2, "Reaping pid %d\n", ipmi->i_pid);
kill(ipmi->i_pid, 9);
waitpid(ipmi->i_pid, NULL, 0);
}
ipmi->i_pid = -1;
if (ipmi->i_rdfd >= 0) {
close(ipmi->i_rdfd);
ipmi->i_rdfd = -1;
}
if (ipmi->i_wrfd >= 0) {
close(ipmi->i_wrfd);
ipmi->i_wrfd = -1;
}
return 0;
}
static int
ipmi_expect(struct ipmi *ipmi, struct Etoken *toklist, int timeout)
{
int ret;
char buf[32768]; /* XX hope this is enough */
dbg_printf(ipmi, 3, "Looking for: \n");
for (ret = 0; toklist[ret].string; ret++) {
dbg_printf(ipmi, 3, " '%s', val = %d\n",
toklist[ret].string,
toklist[ret].toktype);
}
ret = ExpectToken(ipmi->i_rdfd, toklist, timeout, buf, sizeof(buf));
dbg_printf(ipmi, 3, "ExpectToken returned %d\n", ret);
if (ret == -1) {
ret = errno;
dbg_printf(ipmi, 3, "ExpectToken failed. Info returned:\n");
dbg_printf(ipmi, 3, ">>>>>\n%s\n<<<<<\nError = %d (%s)\n",
buf,
ret,
strerror(ret));
}
return ret;
}
static int
ipmi_op(struct ipmi *ipmi, int op, struct Etoken *toklist)
{
char cmd[2048];
int ret;
build_cmd(cmd, sizeof(cmd), ipmi, op);
if (ipmi_spawn(ipmi, cmd) != 0)
return -1;
ret = ipmi_expect(ipmi, toklist, ipmi->i_timeout);
ipmi_reap(ipmi);
if (ret == EFAULT) {
log(LOG_CRIT, "ipmilan: ipmitool failed to create "
"mutex; unable to complete operation\n");
return ret;
}
if (ret == ECIPHER) {
log(LOG_CRIT, "ipmilan: ipmitool failed to operate "
"with ciphersuite %d; unable to complete operation\n",ipmi->i_cipher);
return ret;
}
if (ret == ESTATE) {
log(LOG_CRIT, "ipmilan: ipmitool failed to complete "
"command in current state\n");
return ret;
}
if (ret == ETIMEDOUT) {
/*!!! Still couldn't get through?! */
log(LOG_WARNING,
"ipmilan: Failed to connect after %d seconds\n",ipmi->i_timeout);
}
return ret;
}
static int
ipmi_off(struct ipmi *ipmi)
{
int ret, retries = 7;
ret = ipmi_op(ipmi, ST_STATUS, power_status);
switch(ret) {
case STATE_ON:
break;
case STATE_OFF:
return 0;
default:
return ret;
}
while (retries>=0) {
ret = ipmi_op(ipmi, ST_POWEROFF, power_off_complete);
if (ret != 0)
return ret;
sleep(2);
--retries;
ret = ipmi_op(ipmi, ST_STATUS, power_status);
switch(ret) {
case STATE_OFF:
return 0;
case EFAULT:
/* We're done. */
retries = 0;
break;
case STATE_ON:
default:
continue;
}
}
log(LOG_WARNING, "ipmilan: Power still on\n");
return ret;
}
static int
ipmi_on(struct ipmi *ipmi)
{
int ret, retries = 7;
ret = ipmi_op(ipmi, ST_STATUS, power_status);
switch(ret) {
case STATE_ON:
return 0;
case STATE_OFF:
break;
default:
return ret;
}
while (retries>=0) {
ret = ipmi_op(ipmi, ST_POWERON, power_on_complete);
if (ret != 0)
return ret;
sleep(ipmi->i_power_wait);
--retries;
ret = ipmi_op(ipmi, ST_STATUS, power_status);
switch(ret) {
case STATE_ON:
return 0;
case EFAULT:
/* We're done. */
retries = 0;
break;
case STATE_OFF:
default:
continue;
}
}
log(LOG_WARNING, "ipmilan: Power still off\n");
return ret;
}
static int
ipmi_cycle(struct ipmi *ipmi)
{
int ret;
ret = ipmi_op(ipmi, ST_CYCLE, power_cycle_complete);
return ret;
}
static int
ipmi_diag(struct ipmi *ipmi)
{
int ret;
ret = ipmi_op(ipmi, ST_DIAG, power_off_complete);
return ret;
}
/**
Squash all our private data
*/
static void
ipmi_destroy(struct ipmi *i)
{
ipmi_reap(i);
if (i->i_user) {
free(i->i_user);
i->i_user = NULL;
}
if (i->i_password) {
free(i->i_password);
i->i_password= NULL;
}
if (i->i_host) {
free(i->i_host);
i->i_host = NULL;
}
i->i_config = 0;
i->i_id = NOTIPMI;
}
/**
Multipurpose initializer. Used to either create a new, blank ipmi,
or update an existing one, or both.
*/
static struct ipmi *
ipmi_init(struct ipmi *i, char *host, char *authtype,
char *user, char *password, int lanplus, int verbose,int timeout,
int power_wait,
int cipher)
{
const char *p;
if (!i || !i->i_ipmitool)
p = ipmitool_path();
else
p = i->i_ipmitool;
if (!p) {
log(LOG_WARNING, "ipmilan: ipmitool not found!\n");
return NULL;
}
if (!i)
i = malloc (sizeof(*i));
if (!i)
return NULL;
if (host && strlen(host)) {
i->i_host = strdup(host);
if (!i->i_host) {
free(i);
return NULL;
}
} else
i->i_host = NULL;
if (password && strlen(password)) {
i->i_password = strdup(password);
if (!i->i_password) {
free(i->i_host);
free(i);
return NULL;
}
} else
i->i_password = NULL;
if (authtype && strlen(authtype)) {
i->i_authtype = strdup(authtype);
if (!i->i_authtype) {
free(i->i_host);
if (i->i_password)
free(i->i_password);
free(i);
return NULL;
}
} else
i->i_authtype = NULL;
if (user && strlen(user)) {
i->i_user= strdup(user);
if (!i->i_user) {
free(i->i_host);
if (i->i_authtype)
free(i->i_authtype);
if (i->i_password)
free(i->i_password);
free(i);
return NULL;
}
} else
i->i_user = NULL;
i->i_ipmitool = p;
i->i_rdfd = -1;
i->i_wrfd = -1;
i->i_pid = -1;
i->i_id = IPMIID;
i->i_verbose = verbose;
i->i_lanplus = lanplus;
i->i_timeout = timeout;
i->i_power_wait = power_wait;
i->i_cipher = cipher;
return i;
}
/**
Remove leading and trailing whitespace from a line of text.
*/
static int
cleanup(char *line, size_t linelen)
{
char *p;
size_t x;
/* Remove leading whitespace. */
p = line;
for (x = 0; x <= linelen; x++) {
switch (line[x]) {
case '\t':
case ' ':
break;
case '\n':
case '\r':
return -1;
default:
goto eol;
}
}
eol:
/* Move the remainder down by as many whitespace chars as we
chewed up */
if (x)
memmove(p, &line[x], linelen-x);
/* Remove trailing whitespace. */
for (x=0; x <= linelen; x++) {
switch(line[x]) {
case '\t':
case ' ':
case '\r':
case '\n':
line[x] = 0;
case 0:
/* End of line */
return 0;
}
}
return -1;
}
/**
Parse args from stdin. Dev + devlen + op + oplen must be valid.
*/
static int
get_options_stdin(char *ip, size_t iplen,
char *authtype, size_t atlen,
char *passwd, size_t pwlen,
char *pwd_script, size_t pwd_script_len,
char *user, size_t userlen,
char *op, size_t oplen,
int *lanplus, int *verbose,int *timeout,
int *power_wait,
int *cipher, char *method, int methodlen,
char *delay, size_t delaylen)
{
char in[256];
int line = 0;
char *name, *val;
op[0] = 0;
method[0] = 0;
while (fgets(in, sizeof(in), stdin)) {
++line;
if (in[0] == '#')
continue;
if (cleanup(in, sizeof(in)) == -1)
continue;
name = in;
if ((val = strchr(in, '='))) {
*val = 0;
++val;
}
if (!strcasecmp(name, "agent")) {
/* Used by fenced? */
} else if (!strcasecmp(name, "verbose")) {
*verbose = 1;
} else if (!strcasecmp(name, "ipaddr")) {
/* IP address to use. E.g. 10.1.1.2 */
if (val)
strncpy(ip, val, iplen);
else
ip[0] = 0;
} else if (!strcasecmp(name, "auth")) {
/* Authtype to use */
if (val)
strncpy(authtype, val, atlen);
else
authtype[0] = 0;
} else if (!strcasecmp(name, "passwd")) {
/* password */
if (val)
strncpy(passwd, val, pwlen);
else
passwd[0] = 0;
} else if (!strcasecmp(name, "passwd_script")) {
if (val) {
strncpy(pwd_script, val, pwd_script_len);
pwd_script[pwd_script_len - 1] = '\0';
} else
pwd_script[0] = '\0';
} else if (!strcasecmp(name, "user") || !strcasecmp(name, "login")) {
/* username */
if (val)
strncpy(user, val, userlen);
else
user[0] = 0;
} else if (!strcasecmp(name, "lanplus")) {
(*lanplus) = 1;
} else if (!strcasecmp(name,"timeout")) {
if ((sscanf(val,"%d",timeout)!=1) || *timeout<1) {
*timeout=DEFAULT_TIMEOUT;
}
} else if (!strcasecmp(name,"power_wait")) {
if ((sscanf(val,"%d",power_wait)!=1) || *power_wait<1) {
*power_wait=DEFAULT_POWER_WAIT;
}
} else if (!strcasecmp(name,"cipher")) {
if ((sscanf(val,"%d",cipher)!=1) || *cipher<0) {
*cipher=-1;
}
} else if (!strcasecmp(name,"method")) {
strncpy (method, val, methodlen);
} else if (!strcasecmp(name, "option") ||
!strcasecmp(name, "operation") ||
!strcasecmp(name, "action")) {
if (val)
strncpy(op, val, oplen);
else
op[0] = 0;
} else if (!strcasecmp(name,"delay")) {
if (val)
strncpy(delay, val, delaylen);
else
delay[0] = 0;
}
}
return 0;
}
/**
Print a message to stderr and call exit(1).
*/
static void
fail_exit(const char *msg)
{
fprintf(stderr, "failed: %s\n", msg);
exit(1);
}
static void
usage_exit(char *pname)
{
printf("usage: %s <options>\n", pname);
printf(" -A <authtype> IPMI Lan Auth type (md5, password, or none)\n");
printf(" -a <ipaddr> IPMI Lan IP to talk to\n");
printf(" -i <ipaddr> IPMI Lan IP to talk to (deprecated, use -a)\n");
printf(" -p <password> Password (if required) to control power on\n"
" IPMI device\n");
printf(" -P Use Lanplus\n");
printf(" -S <path> Script to retrieve password (if required)\n");
printf(" -l <login> Username/Login (if required) to control power\n"
" on IPMI device\n");
printf(" -o <op> Operation to perform.\n");
printf(" Valid operations: on, off, reboot, status,\n");
printf(" diag, list or monitor\n");
printf(" -t <timeout> Timeout (sec) for IPMI operation (default %d)\n",DEFAULT_TIMEOUT);
printf(" -T <timeout> Wait X seconds after on/off operation\n");
printf(" -f <timeout> Wait X seconds before fencing is started\n");
printf(" -C <cipher> Ciphersuite to use (same as ipmitool -C parameter)\n");
printf(" -M <method> Method to fence (onoff or cycle (default %s)\n", DEFAULT_METHOD);
printf(" -V Print version and exit\n");
printf(" -v Verbose mode\n\n");
printf("If no options are specified, the following options will be read\n");
printf("from standard input (one per line):\n\n");
printf(" auth=<auth> Same as -A\n");
printf(" ipaddr=<#> Same as -a\n");
printf(" passwd=<pass> Same as -p\n");
printf(" passwd_script=<path> Same as -S\n");
printf(" lanplus Same as -P\n");
printf(" login=<login> Same as -u\n");
printf(" option=<op> Same as -o\n");
printf(" operation=<op> Same as -o\n");
printf(" action=<op> Same as -o\n");
printf(" delay=<seconds> Same as -f\n");
printf(" timeout=<timeout> Same as -t\n");
printf(" power_wait=<time> Same as -T\n");
printf(" cipher=<cipher> Same as -C\n");
printf(" method=<method> Same as -M\n");
printf(" verbose Same as -v\n\n");
exit(1);
}
/** Print XML metadata of fence agent*/
static void print_xml_metadata(char *pname) {
int i;
printf("%s\n","<?xml version=\"1.0\" ?>");
printf("%s%s%s\n","<resource-agent name=\"",pname,"\" shortdesc=\"Fence agent for IPMI over LAN\">");
printf("<longdesc>\n");
printf("fence_ipmilan is an I/O Fencing agent which can be used with "
"machines controlled by IPMI. This agent calls support software "
"using ipmitool (http://ipmitool.sf.net/).\n\n"
"To use fence_ipmilan with HP iLO 3 you have to enable lanplus "
"option (lanplus / -P) and increase wait after operation to "
"4 seconds (power_wait=4 / -T 4)");
printf("</longdesc>\n");
printf("%s\n","<parameters>");
for (i=0;i<(sizeof(xml_parameters)/sizeof(struct xml_parameter_s));i++) {
printf("\t<parameter name=\"%s\" unique=\"1\">\n",xml_parameters[i].name);
printf("\t\t<getopt mixed=\"%s\" />\n",xml_parameters[i].getopt);
if (xml_parameters[i].default_value == NULL) {
printf("\t\t<content type=\"%s\" />\n",xml_parameters[i].content_type);
} else {
printf("\t\t<content type=\"%s\" default=\"%s\"/>\n", \
xml_parameters[i].content_type, \
xml_parameters[i].default_value );
}
printf("\t\t<shortdesc lang=\"en\">");
printf("%s",xml_parameters[i].description);
printf("</shortdesc>\n");
printf("\t</parameter>\n");
}
printf("%s\n","</parameters>");
printf("%s\n","<actions>");
printf("\t<action name=\"%s\" />\n", "on");
printf("\t<action name=\"%s\" />\n", "off");
printf("\t<action name=\"%s\" />\n", "reboot");
printf("\t<action name=\"%s\" />\n", "status");
printf("\t<action name=\"%s\" />\n", "diag");
printf("\t<action name=\"%s\" />\n", "list");
printf("\t<action name=\"%s\" />\n", "monitor");
printf("\t<action name=\"%s\" />\n", "metadata");
printf("%s\n","</actions>");
printf("%s\n","</resource-agent>");
}
int
main(int argc, char **argv)
{
extern char *optarg;
int opt, ret = -1;
char authtype[64];
char ip[64];
char passwd[64];
char user[64];
char op[64];
char method[64];
char delay[64];
char pwd_script[PATH_MAX] = { 0, };
int lanplus=0;
int verbose=0;
char *pname = basename(argv[0]);
struct ipmi *i;
int timeout=DEFAULT_TIMEOUT;
int down_sleep=DEFAULT_POWER_WAIT;
int cipher=-1;
int print_final_status=1;
int translated_ret = -1;
memset(ip, 0, sizeof(ip));
memset(authtype, 0, sizeof(authtype));
memset(passwd, 0, sizeof(passwd));
memset(user, 0, sizeof(user));
memset(op, 0, sizeof(op));
memset(method, 0, sizeof(method));
memset(delay, 0, sizeof(delay));
if (argc > 1) {
/*
Parse command line options if any were specified
*/
while ((opt = getopt(argc, argv, "A:a:i:l:p:S:Po:vV?hHt:T:C:M:f:")) != EOF) {
switch(opt) {
case 'A':
/* Auth type */
strncpy(authtype, optarg, sizeof(authtype));
break;
case 'a':
case 'i':
/* IP address */
strncpy(ip, optarg, sizeof(ip));
break;
case 'l':
/* user / login */
strncpy(user, optarg, sizeof(user));
break;
case 'p':
/* password */
strncpy(passwd, optarg, sizeof(passwd));
break;
case 'P':
lanplus = 1;
break;
case 'S':
strncpy(pwd_script, optarg, sizeof(pwd_script));
pwd_script[sizeof(pwd_script) - 1] = '\0';
break;
case 'o':
/* Operation */
strncpy(op, optarg, sizeof(op));
break;
case 'f':
/* Delay */
strncpy(delay, optarg, sizeof(delay));
break;
case 't':
/* Timeout */
if ((sscanf(optarg,"%d",&timeout)!=1) || timeout<1) {
fail_exit("Timeout option expects positive number parameter");
}
break;
case 'T':
/* Shutdown Sleep Time */
if ((sscanf(optarg,"%d",&down_sleep)!=1) || down_sleep<1) {
fail_exit("Shutdown time option expects positive number parameter");
}
break;
case 'C':
/* Ciphersuite */
if ((sscanf(optarg,"%d",&cipher)!=1) || cipher<0) {
fail_exit("Ciphersuite option expects positive number parameter");
}
break;
case 'M':
/* Reboot method */
strncpy(method, optarg, sizeof(method));
break;
case 'v':
verbose++;
break;
case 'V':
printf("%s %s (built %s %s)\n", pname,
VERSION,
__DATE__, __TIME__);
printf("%s\n",
REDHAT_COPYRIGHT);
return 0;
default:
usage_exit(pname);
}
}
} else {
/*
No command line args? Get stuff from stdin
*/
if (get_options_stdin(ip, sizeof(ip),
authtype, sizeof(authtype),
passwd, sizeof(passwd),
pwd_script, sizeof(pwd_script),
user, sizeof(user),
op, sizeof(op), &lanplus, &verbose,&timeout,
&down_sleep,
&cipher, method, sizeof(method),
delay, sizeof(delay)) != 0)
return 1;
}
if (pwd_script[0] != '\0') {
char pwd_buf[1024];
FILE *fp;
fp = popen(pwd_script, "r");
if (fp != NULL) {
ssize_t len = fread(pwd_buf, 1, sizeof(pwd_buf), fp);
if (len > 0) {
char *p;
p = strchr(pwd_buf, '\n');
if (p != NULL)
*p = '\0';
p = strchr(pwd_buf, '\r');
if (p != NULL)
*p = '\0';
strncpy(passwd, pwd_buf, sizeof(passwd));
passwd[sizeof(passwd) - 1] = '\0';
}
pclose(fp);
}
}
if (!strcasecmp(op, "metadata")) {
print_xml_metadata(pname);
translated_ret = ERR_OK;
ret=0;
print_final_status=0;
goto metaout;
}
/*
Validate the operating parameters
*/
if (strlen(ip) == 0)
fail_exit("no IP address specified");
if (!strlen(op))
snprintf(op,sizeof(op), "reboot");
if (!strlen(method))
snprintf(method, sizeof(method), "onoff");
if (strcasecmp(op, "off") && strcasecmp(op, "on") &&
strcasecmp(op, "status") && strcasecmp(op, "reboot") &&
strcasecmp(op, "monitor") && strcasecmp(op, "list") &&
strcasecmp(op, "metadata") && strcasecmp(op, "diag")) {
fail_exit("operation must be 'on', 'off', 'status', "
"'reboot', 'diag', 'list', 'monitor' or 'metadata'");
}
if (strlen(authtype) &&
strcasecmp(authtype, "md5") &&
strcasecmp(authtype, "password") &&
strcasecmp(authtype, "none")) {
fail_exit("authtype, if included, must be 'md5', 'password',"
" 'none'.");
}
if (strcasecmp(method, "onoff") &&
strcasecmp(method, "cycle")) {
fail_exit("method, if included, muse be 'onoff', 'cycle'.");
}
if (!strcasecmp(method, "cycle") &&
(!strcasecmp(op, "on") || !strcasecmp(op, "off"))) {
fail_exit("cycle method supports only 'reboot' operation (not 'on' or 'off').");
}
/* Delay fencing if requested */
if (delay) {
if (!strcasecmp(op, "reboot") || !strcasecmp(op, "off")) {
sleep(atoi(delay));
}
}
/* Ok, set up the IPMI struct */
i = ipmi_init(NULL, ip, authtype, user, passwd, lanplus, verbose, timeout, down_sleep, cipher);
if (!i)
fail_exit("Failed to initialize\n");
/*
Perform the requested operation
*/
if (!strcasecmp(op, "reboot")) {
printf("Rebooting machine @ IPMI:%s...", ip);
fflush(stdout);
if (!strcasecmp(method, "cycle")) {
ret = ipmi_op(i, ST_STATUS, power_status);
if (ret == STATE_OFF) {
/* State is off -> use onoff method because cycle is not able to turn on*/
snprintf(method, sizeof(method), "onoff");
}
}
if (!strcasecmp(method, "cycle")) {
ret = ipmi_cycle(i);
} else {
/* Original onoff method */
ret = ipmi_off(i);
translated_ret = (ret==0?ERR_OFF_SUCCESSFUL:ERR_OFF_FAIL);
if (ret != 0) {
goto out;
}
ret = ipmi_on(i);
}
} else if (!strcasecmp(op, "on")) {
printf("Powering on machine @ IPMI:%s...", ip);
fflush(stdout);
ret = ipmi_on(i);
translated_ret = (ret==0?ERR_ON_SUCCESSFUL:ERR_ON_FAIL);
} else if (!strcasecmp(op, "off")) {
printf("Powering off machine @ IPMI:%s...", ip);
fflush(stdout);
ret = ipmi_off(i);
translated_ret = (ret==0?ERR_ON_SUCCESSFUL:ERR_ON_FAIL);
} else if (!strcasecmp(op, "status") || !strcasecmp(op, "monitor")) {
printf("Getting status of IPMI:%s...",ip);
fflush(stdout);
ret = ipmi_op(i, ST_STATUS, power_status);
switch(ret) {
case STATE_ON:
if (!strcasecmp(op, "status"))
printf("Chassis power = On\n");
translated_ret = ERR_STATUS_ON;
ret = 0;
break;
case STATE_OFF:
if (!strcasecmp(op, "status"))
printf("Chassis power = Off\n");
translated_ret = ERR_STATUS_OFF;
ret = 0;
break;
default:
if (!strcasecmp(op, "status"))
printf("Chassis power = Unknown\n");
translated_ret = ERR_STATUS_FAIL;
ret = 1;
break;
}
} else if (!strcasecmp(op, "list")) {
printf("%s\n","N/A");
ret=0;
translated_ret = ERR_OK;
print_final_status=0;
} else if (!strcasecmp(op, "diag")) {
printf("Pulsing diagnostic interrupt to machine @ IPMI:%s...", ip);
fflush(stdout);
ret = ipmi_diag(i);
translated_ret = (ret==0?ERR_ON_SUCCESSFUL:ERR_ON_FAIL);
ret = 0;
}
out:
ipmi_destroy(i);
free(i);
metaout:
if (print_final_status) {
if (ret == 0)
printf("Done\n");
else
printf("Failed\n");
}
if (!strcasecmp(op, "monitor"))
translated_ret = ret;
if (!strcasecmp(op, "diaf")) {
/** .. but when a system receive the DIAG signal , it
** switches to a kdump kernel, but the machine is always
** "on" during the dump phase. It only become temporarily
** "off" at the end of the dump just before rebooting.
**/
translated_ret = 0;
}
return translated_ret;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Feb 24, 9:44 PM (13 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1464472
Default Alt Text
ipmilan.c (28 KB)
Attached To
Mode
rF Fence Agents
Attached
Detach File
Event Timeline
Log In to Comment