mirror of https://github.com/sipwise/heartbeat.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
584 lines
13 KiB
584 lines
13 KiB
/*
|
|
* Stonith API infrastructure.
|
|
*
|
|
* Copyright (c) 2000 Alan Robertson <alanr@unix.sh>
|
|
*
|
|
* 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
|
|
*
|
|
*/
|
|
#include <lha_internal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <syslog.h>
|
|
#include <sys/wait.h>
|
|
#include <sys/param.h>
|
|
#include <dlfcn.h>
|
|
#include <dirent.h>
|
|
#include <glib.h>
|
|
#define ENABLE_PIL_DEFS_PRIVATE
|
|
#include <pils/plugin.h>
|
|
#include <pils/generic.h>
|
|
#include <stonith/stonith.h>
|
|
#include <stonith/stonith_plugin.h>
|
|
|
|
|
|
#define MALLOC StonithPIsys->imports->alloc
|
|
#define MALLOCT(t) (t*)(MALLOC(sizeof(t)))
|
|
#define REALLOC StonithPIsys->imports->mrealloc
|
|
#define STRDUP StonithPIsys->imports->mstrdup
|
|
#define FREE(p) {StonithPIsys->imports->mfree(p); (p) = NULL;}
|
|
|
|
#define LOG(args...) PILCallLog(StonithPIsys->imports->log, args)
|
|
|
|
#define EXTPINAME_S "external"
|
|
|
|
PILPluginUniv* StonithPIsys = NULL;
|
|
static GHashTable* Splugins = NULL;
|
|
static int init_pluginsys(void);
|
|
extern StonithImports stonithimports;
|
|
|
|
static PILGenericIfMgmtRqst Reqs[] =
|
|
{
|
|
{STONITH_TYPE_S, &Splugins, &stonithimports, NULL, NULL},
|
|
{NULL, NULL, NULL, NULL, NULL}
|
|
};
|
|
|
|
void PILpisysSetDebugLevel(int);
|
|
/* Initialize the plugin system... */
|
|
static int
|
|
init_pluginsys(void) {
|
|
|
|
if (StonithPIsys) {
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/* PILpisysSetDebugLevel(10); */
|
|
StonithPIsys = NewPILPluginUniv(STONITH_MODULES);
|
|
|
|
if (StonithPIsys) {
|
|
if (PILLoadPlugin(StonithPIsys, PI_IFMANAGER, "generic", Reqs)
|
|
!= PIL_OK){
|
|
fprintf(stderr, "generic plugin load failed\n");
|
|
DelPILPluginUniv(StonithPIsys);
|
|
StonithPIsys = NULL;
|
|
}
|
|
/*PILSetDebugLevel(StonithPIsys, PI_IFMANAGER, "generic", 10);*/
|
|
}else{
|
|
fprintf(stderr, "pi univ creation failed\n");
|
|
}
|
|
return StonithPIsys != NULL;
|
|
}
|
|
|
|
/*
|
|
* Create a new Stonith object of the requested type.
|
|
*/
|
|
|
|
Stonith *
|
|
stonith_new(const char * type)
|
|
{
|
|
StonithPlugin * sp = NULL;
|
|
struct stonith_ops* ops = NULL;
|
|
char * key;
|
|
char * subplugin;
|
|
char * typecopy;
|
|
|
|
|
|
if (!init_pluginsys()) {
|
|
return NULL;
|
|
}
|
|
|
|
if ((typecopy = STRDUP(type)) == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
if (((subplugin = strchr(typecopy, '/')) != NULL) &&
|
|
(strncmp(EXTPINAME_S, typecopy, strlen(EXTPINAME_S)) == 0)) {
|
|
*subplugin++ = 0; /* make two strings */
|
|
}
|
|
|
|
/* Look and see if it's already loaded... */
|
|
|
|
if (g_hash_table_lookup_extended(Splugins, typecopy
|
|
, (gpointer)&key, (gpointer)&ops)) {
|
|
/* Yes! Increment reference count */
|
|
PILIncrIFRefCount(StonithPIsys, STONITH_TYPE_S, typecopy, 1);
|
|
|
|
}else{ /* No. Try and load it... */
|
|
if (PILLoadPlugin(StonithPIsys, STONITH_TYPE_S, typecopy, NULL)
|
|
!= PIL_OK) {
|
|
FREE(typecopy);
|
|
return NULL;
|
|
}
|
|
|
|
/* Look up the plugin in the Splugins table */
|
|
if (!g_hash_table_lookup_extended(Splugins, typecopy
|
|
, (void*)&key, (void*)&ops)) {
|
|
/* OOPS! didn't find it(!?!)... */
|
|
PILIncrIFRefCount(StonithPIsys, STONITH_TYPE_S
|
|
, typecopy, -1);
|
|
FREE(typecopy);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (ops != NULL) {
|
|
sp = ops->new((const char *)(subplugin));
|
|
if (sp != NULL) {
|
|
sp->s.stype = STRDUP(typecopy);
|
|
}
|
|
}
|
|
|
|
FREE(typecopy);
|
|
return sp ? (&sp->s) : NULL;
|
|
}
|
|
|
|
static int
|
|
qsort_string_cmp(const void *a, const void *b)
|
|
{
|
|
return(strcmp(*(const char * const *)a, *(const char * const *)b));
|
|
}
|
|
|
|
/*
|
|
* Return list of STONITH types valid in stonith_new()
|
|
*/
|
|
|
|
char **
|
|
stonith_types(void)
|
|
{
|
|
int plugincount;
|
|
static char ** lasttypelist = NULL;
|
|
char ** newtypelist;
|
|
int extplugin = -1;
|
|
|
|
if (!init_pluginsys()) {
|
|
return NULL;
|
|
}
|
|
|
|
if (lasttypelist) {
|
|
stonith_free_hostlist(lasttypelist);
|
|
lasttypelist = NULL;
|
|
}
|
|
|
|
newtypelist = PILListPlugins(StonithPIsys, STONITH_TYPE_S, NULL);
|
|
if (newtypelist == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
/* look for 'external' plugin */
|
|
for (plugincount=0; newtypelist[plugincount] != NULL; ++plugincount) {
|
|
if (strcmp(newtypelist[plugincount], EXTPINAME_S) == 0) {
|
|
extplugin = plugincount;
|
|
}
|
|
}
|
|
|
|
if (extplugin >= 0) {
|
|
/* 'external' plugin exists, adjust types list by replacing
|
|
* 'external' with sorted list of 'external/subplugin' */
|
|
const char **extPI, **p;
|
|
int numextPI, i, index;
|
|
Stonith * ext;
|
|
|
|
/* let the external plugin return a list */
|
|
if ((ext = stonith_new(EXTPINAME_S)) == NULL) {
|
|
LOG(PIL_CRIT, "Cannot create new external "
|
|
"plugin object");
|
|
goto types_exit;
|
|
}
|
|
if ((extPI = stonith_get_confignames(ext)) == NULL) {
|
|
LOG(PIL_CRIT, "Cannot get external plugin subplugins");
|
|
stonith_delete(ext);
|
|
goto types_exit;
|
|
}
|
|
|
|
/* count the external plugins */
|
|
for (numextPI = 0, p = extPI; *p; p++, numextPI++);
|
|
|
|
/* sort the external plugins */
|
|
qsort(extPI, numextPI, sizeof(char *), qsort_string_cmp);
|
|
|
|
/* allocate types list (don't need numextPI+plugincount+1
|
|
* because 'external' is being removed from list */
|
|
lasttypelist = (char **)
|
|
MALLOC((numextPI+plugincount) * sizeof(char *));
|
|
if (lasttypelist == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
stonith_delete(ext);
|
|
goto types_exit;
|
|
}
|
|
|
|
memset(lasttypelist, 0, (numextPI+plugincount)*sizeof(char *));
|
|
|
|
/* copy plugins up to but not including 'external' */
|
|
for (index = 0, i = 0; i < extplugin; index++, i++) {
|
|
lasttypelist[index] = STRDUP(newtypelist[i]);
|
|
if (lasttypelist[index] == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
stonith_delete(ext);
|
|
goto types_exit_mem;
|
|
}
|
|
}
|
|
|
|
/* copy external plugins */
|
|
for (i = 0; i < numextPI; index++, i++) {
|
|
int len = strlen(EXTPINAME_S) +
|
|
strlen(extPI[i]) + 2;
|
|
lasttypelist[index] = MALLOC(len * sizeof(char *));
|
|
if (lasttypelist[index] == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
stonith_delete(ext);
|
|
goto types_exit_mem;
|
|
}
|
|
snprintf(lasttypelist[index], len, "%s/%s"
|
|
, EXTPINAME_S, extPI[i]);
|
|
}
|
|
|
|
/* copy plugins after 'external' */
|
|
for (i = extplugin+1; i < plugincount; index++, i++) {
|
|
lasttypelist[index] = STRDUP(newtypelist[i]);
|
|
if (lasttypelist[index] == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
stonith_delete(ext);
|
|
goto types_exit_mem;
|
|
}
|
|
}
|
|
|
|
stonith_delete(ext);
|
|
}else{
|
|
/* 'external' plugin doesn't exist, copy types list */
|
|
char **from, **to;
|
|
|
|
lasttypelist = (char**)MALLOC((plugincount+1) * sizeof(char *));
|
|
if (lasttypelist == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
goto types_exit;
|
|
}
|
|
|
|
for (from = newtypelist, to = lasttypelist
|
|
; *from
|
|
; ++from, ++to) {
|
|
*to = STRDUP(*from);
|
|
if (*to == NULL) {
|
|
LOG(PIL_CRIT, "Out of memory");
|
|
goto types_exit_mem;
|
|
}
|
|
}
|
|
*to = NULL;
|
|
}
|
|
goto types_exit;
|
|
|
|
types_exit_mem:
|
|
stonith_free_hostlist(lasttypelist);
|
|
lasttypelist = NULL;
|
|
types_exit:
|
|
PILFreePluginList(newtypelist);
|
|
return lasttypelist;
|
|
}
|
|
|
|
/* Destroy the STONITH object... */
|
|
|
|
void
|
|
stonith_delete(Stonith *s)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
|
|
if (sp && sp->s_ops) {
|
|
char * st = sp->s.stype;
|
|
sp->s_ops->destroy(sp);
|
|
PILIncrIFRefCount(StonithPIsys, STONITH_TYPE_S, st, -1);
|
|
/* destroy should not free it */
|
|
FREE(st);
|
|
}
|
|
}
|
|
|
|
const char **
|
|
stonith_get_confignames(Stonith* s)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
|
|
if (sp && sp->s_ops) {
|
|
return sp->s_ops->get_confignames(sp);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
const char*
|
|
stonith_get_info(Stonith* s, int infotype)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
|
|
if (sp && sp->s_ops) {
|
|
return sp->s_ops->get_info(sp, infotype);
|
|
}
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void
|
|
stonith_set_debug (Stonith* s, int debuglevel)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
if (StonithPIsys == NULL) {
|
|
return;
|
|
}
|
|
PILSetDebugLevel(StonithPIsys, STONITH_TYPE_S, sp->s.stype, debuglevel);
|
|
}
|
|
|
|
void
|
|
stonith_set_log(Stonith* s, PILLogFun logfun)
|
|
{
|
|
if (StonithPIsys == NULL) {
|
|
return;
|
|
}
|
|
PilPluginUnivSetLog(StonithPIsys, logfun);
|
|
}
|
|
|
|
int
|
|
stonith_set_config(Stonith* s, StonithNVpair* list)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
|
|
if (sp && sp->s_ops) {
|
|
int rc = sp->s_ops->set_config(sp, list);
|
|
if (rc == S_OK) {
|
|
sp->isconfigured = TRUE;
|
|
}
|
|
return rc;
|
|
}
|
|
return S_INVAL;
|
|
}
|
|
|
|
/*
|
|
* FIXME: We really ought to support files with name=value type syntax
|
|
* on each line...
|
|
*
|
|
*/
|
|
int
|
|
stonith_set_config_file(Stonith* s, const char * configname)
|
|
{
|
|
FILE * cfgfile;
|
|
|
|
char line[1024];
|
|
|
|
if ((cfgfile = fopen(configname, "r")) == NULL) {
|
|
LOG(PIL_CRIT, "Cannot open %s", configname);
|
|
return(S_BADCONFIG);
|
|
}
|
|
while (fgets(line, sizeof(line), cfgfile) != NULL){
|
|
int len;
|
|
|
|
if (*line == '#' || *line == '\n' || *line == EOS) {
|
|
continue;
|
|
}
|
|
|
|
/*remove the new line in the end*/
|
|
len = strnlen(line, sizeof(line)-1);
|
|
if (line[len-1] == '\n'){
|
|
line[len-1] = '\0';
|
|
}else{
|
|
line[len] = '\0';
|
|
}
|
|
|
|
fclose(cfgfile);
|
|
return stonith_set_config_info(s, line);
|
|
}
|
|
fclose(cfgfile);
|
|
return S_BADCONFIG;
|
|
}
|
|
|
|
int
|
|
stonith_set_config_info(Stonith* s, const char * info)
|
|
{
|
|
StonithNVpair* cinfo;
|
|
int rc;
|
|
cinfo = stonith1_compat_string_to_NVpair(s, info);
|
|
if (cinfo == NULL) {
|
|
return S_BADCONFIG;
|
|
}
|
|
rc = stonith_set_config(s, cinfo);
|
|
free_NVpair(cinfo); cinfo = NULL;
|
|
return rc;
|
|
}
|
|
|
|
char**
|
|
stonith_get_hostlist(Stonith* s)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
if (sp && sp->s_ops && sp->isconfigured) {
|
|
return sp->s_ops->get_hostlist(sp);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
stonith_free_hostlist(char** hostlist)
|
|
{
|
|
char ** here;
|
|
|
|
for (here=hostlist; *here; ++here) {
|
|
FREE(*here);
|
|
}
|
|
FREE(hostlist);
|
|
}
|
|
|
|
int
|
|
stonith_get_status(Stonith* s)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
if (sp && sp->s_ops && sp->isconfigured) {
|
|
return sp->s_ops->get_status(sp);
|
|
}
|
|
return S_INVAL;
|
|
}
|
|
|
|
int
|
|
stonith_req_reset(Stonith* s, int operation, const char* node)
|
|
{
|
|
StonithPlugin* sp = (StonithPlugin*)s;
|
|
if (sp && sp->s_ops && sp->isconfigured) {
|
|
char* nodecopy = STRDUP(node);
|
|
int rc;
|
|
if (nodecopy == NULL) {
|
|
return S_OOPS;
|
|
}
|
|
g_strdown(nodecopy);
|
|
|
|
rc = sp->s_ops->req_reset(sp, operation, nodecopy);
|
|
FREE(nodecopy);
|
|
return rc;
|
|
}
|
|
return S_INVAL;
|
|
}
|
|
/* Stonith 1 compatibility: Convert a string to an NVpair set */
|
|
StonithNVpair*
|
|
stonith1_compat_string_to_NVpair(Stonith* s, const char * str)
|
|
{
|
|
/* We make some assumptions that the order of parameters in the
|
|
* result from stonith_get_confignames() matches that which
|
|
* was required from a Stonith1 module.
|
|
* Everything after the last delimiter is passed along as part of
|
|
* the final argument - white space and all...
|
|
*/
|
|
const char ** config_names;
|
|
int n_names;
|
|
int j;
|
|
const char * delims = " \t\n\r\f";
|
|
StonithNVpair* ret;
|
|
|
|
if ((config_names = stonith_get_confignames(s)) == NULL) {
|
|
return NULL;
|
|
}
|
|
for (n_names=0; config_names[n_names] != NULL; ++n_names) {
|
|
/* Just count */;
|
|
}
|
|
ret = (StonithNVpair*) (MALLOC((n_names+1)*sizeof(StonithNVpair)));
|
|
if (ret == NULL) {
|
|
return NULL;
|
|
}
|
|
memset(ret, 0, (n_names+1)*sizeof(StonithNVpair));
|
|
for (j=0; j < n_names; ++j) {
|
|
size_t len;
|
|
if ((ret[j].s_name = STRDUP(config_names[j])) == NULL) {
|
|
goto freeandexit;
|
|
}
|
|
ret[j].s_value = NULL;
|
|
str += strspn(str, delims);
|
|
if (*str == EOS) {
|
|
goto freeandexit;
|
|
}
|
|
if (j == (n_names -1)) {
|
|
len = strlen(str);
|
|
}else{
|
|
len = strcspn(str, delims);
|
|
}
|
|
if ((ret[j].s_value = MALLOC((len+1)*sizeof(char))) == NULL) {
|
|
goto freeandexit;
|
|
}
|
|
memcpy(ret[j].s_value, str, len);
|
|
ret[j].s_value[len] = EOS;
|
|
str += len;
|
|
}
|
|
ret[j].s_name = NULL;
|
|
return ret;
|
|
freeandexit:
|
|
free_NVpair(ret); ret = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
static int NVcur = -1;
|
|
static int NVmax = -1;
|
|
static gboolean NVerr = FALSE;
|
|
|
|
static void
|
|
stonith_walk_ghash(gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
StonithNVpair* u = user_data;
|
|
|
|
if (NVcur <= NVmax && !NVerr) {
|
|
u[NVcur].s_name = STRDUP(key);
|
|
u[NVcur].s_value = STRDUP(value);
|
|
if (u[NVcur].s_name == NULL || u[NVcur].s_value == NULL) {
|
|
/* Memory allocation error */
|
|
NVerr = TRUE;
|
|
return;
|
|
}
|
|
++NVcur;
|
|
}else{
|
|
NVerr = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
StonithNVpair*
|
|
stonith_ghash_to_NVpair(GHashTable* stringtable)
|
|
{
|
|
int hsize = g_hash_table_size(stringtable);
|
|
StonithNVpair* ret;
|
|
|
|
if ((ret = (StonithNVpair*)MALLOC(sizeof(StonithNVpair)*(hsize+1))) == NULL) {
|
|
return NULL;
|
|
}
|
|
NVmax = hsize;
|
|
NVcur = 0;
|
|
ret[hsize].s_name = NULL;
|
|
ret[hsize].s_value = NULL;
|
|
g_hash_table_foreach(stringtable, stonith_walk_ghash, ret);
|
|
NVmax = NVcur = -1;
|
|
if (NVerr) {
|
|
free_NVpair(ret);
|
|
ret = NULL;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void
|
|
free_NVpair(StonithNVpair* nv)
|
|
{
|
|
StonithNVpair* this;
|
|
|
|
if (nv == NULL) {
|
|
return;
|
|
}
|
|
for (this=nv; this->s_name; ++this) {
|
|
FREE(this->s_name);
|
|
if (this->s_value) {
|
|
FREE(this->s_value);
|
|
}
|
|
}
|
|
FREE(nv);
|
|
}
|