diff options
Diffstat (limited to '')
-rw-r--r-- | lib/stonith/stonith.c | 636 |
1 files changed, 636 insertions, 0 deletions
diff --git a/lib/stonith/stonith.c b/lib/stonith/stonith.c new file mode 100644 index 0000000..4ced8c7 --- /dev/null +++ b/lib/stonith/stonith.c @@ -0,0 +1,636 @@ +/* + * 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 +#ifdef MALLOCT +# undef MALLOCT +#endif +#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" +#define RHCSPINAME_S "rhcs" + +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) { + int rc = PILLoadPlugin(StonithPIsys, PI_IFMANAGER, "generic", Reqs); + if (rc != PIL_OK) { + fprintf(stderr, "generic plugin load failed: %d\n", rc); + 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 || + strncmp(RHCSPINAME_S, typecopy, strlen(RHCSPINAME_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() + */ + +static char ** +get_plugin_list(const char *pltype) +{ + char ** typelist = NULL; + const char * const *extPI; + const char * const *p; + int numextPI, i; + Stonith * ext; + + /* let the external plugin return a list */ + if ((ext = stonith_new(pltype)) == NULL) { + LOG(PIL_CRIT, "Cannot create new external " + "plugin object"); + return NULL; + } + if ((extPI = stonith_get_confignames(ext)) == NULL) { + /* don't complain if rhcs plugins are not installed */ + if (strcmp(pltype, "rhcs")) + LOG(PIL_INFO, "Cannot get %s plugin subplugins", pltype); + stonith_delete(ext); + return NULL; + } + + /* count the external plugins */ + for (numextPI = 0, p = extPI; *p; p++, numextPI++); + + typelist = (char **) + MALLOC((numextPI+1)*sizeof(char *)); + if (typelist == NULL) { + LOG(PIL_CRIT, "Out of memory"); + stonith_delete(ext); + return NULL; + } + + memset(typelist, 0, (numextPI + 1)*sizeof(char *)); + + /* copy external plugins */ + for (i = 0; i < numextPI; i++) { + int len = strlen(pltype) + + strlen(extPI[i]) + 2; + typelist[i] = MALLOC(len); + if (typelist[i] == NULL) { + LOG(PIL_CRIT, "Out of memory"); + stonith_delete(ext); + goto err; + } + snprintf(typelist[i], len, "%s/%s" + , pltype, extPI[i]); + } + + stonith_delete(ext); + + /* sort the list of plugin names */ + qsort(typelist, numextPI, sizeof(char *), qsort_string_cmp); + + return typelist; +err: + stonith_free_hostlist(typelist); + return NULL; +} + +char ** +stonith_types(void) +{ + int i, j, cur=0, rl_size, sub_pl = 0; + static char ** rl = NULL; + char ** new_list, **sub_list = NULL; + + if (!init_pluginsys()) { + return NULL; + } + + new_list = PILListPlugins(StonithPIsys, STONITH_TYPE_S, NULL); + if (new_list == NULL) { + return NULL; + } + for (i=0; new_list[i]; ++i) + ; /* count */ + rl_size = i+1; + + rl = (char**)MALLOC(rl_size * sizeof(char *)); + if (rl == NULL) { + LOG(PIL_CRIT, "Out of memory"); + goto types_exit; + } + + for (i=0; new_list[i]; ++i) { + /* look for 'external' and 'rhcs' plugins */ + if (strcmp(new_list[i], EXTPINAME_S) == 0) { + sub_list = get_plugin_list(EXTPINAME_S); + sub_pl = 1; + } else if (strcmp(new_list[i], RHCSPINAME_S) == 0) { + sub_list = get_plugin_list(RHCSPINAME_S); + sub_pl = 1; + } + if (sub_pl) { + if (sub_list) { + for (j=0; sub_list[j]; ++j) + ; /* count */ + rl_size += j; + rl = (char**)REALLOC(rl, rl_size*sizeof(char *)); + for (j=0; sub_list[j]; ++j) { + rl[cur++] = sub_list[j]; + } + FREE(sub_list); + sub_list = NULL; + } + sub_pl = 0; + } else { + rl[cur] = STRDUP(new_list[i]); + if (rl[cur] == NULL) { + LOG(PIL_CRIT, "Out of memory"); + goto types_exit_mem; + } + cur++; + } + } + + rl[cur] = NULL; + goto types_exit; + +types_exit_mem: + stonith_free_hostlist(rl); + rl = NULL; +types_exit: + PILFreePluginList(new_list); + return rl; +} + +/* 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 * const * +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; +} + +void +strdown(char *str) +{ + while( *str ) { + if( isupper(*str) ) + *str = tolower(*str); + str++; + } +} + +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; + } + 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 * const * 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; +} + +StonithNVpair* +stonith_env_to_NVpair(Stonith* s) +{ + /* Read the config names values from the environment */ + const char * const * config_names; + int n_names; + int j; + 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) { + char *env_value; + if ((ret[j].s_name = STRDUP(config_names[j])) == NULL) { + goto freeandexit; + } + env_value = getenv(config_names[j]); + if (env_value) { + if ((ret[j].s_value = STRDUP(env_value)) == NULL) { + goto freeandexit; + } + } else { + ret[j].s_value = NULL; + } + } + 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); +} |