diff --git a/lib/plugins/lrm/raexechb.c b/lib/plugins/lrm/raexechb.c index 8a00f8fb12..7b49ccbfba 100644 --- a/lib/plugins/lrm/raexechb.c +++ b/lib/plugins/lrm/raexechb.c @@ -1,409 +1,413 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 software 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 * General Public License for more details. * * You should have received a copy of the GNU 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 * * File: raexechb.c * Author: Sun Jiang Dong * Copyright (c) 2004 International Business Machines * * This code implements the Resource Agent Plugin Module for LSB style. * It's a part of Local Resource Manager. Currently it's used by lrmd only. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define PIL_PLUGINTYPE RA_EXEC_TYPE #define PIL_PLUGIN heartbeat #define PIL_PLUGINTYPE_S "RAExec" #define PIL_PLUGIN_S "heartbeat" #define PIL_PLUGINLICENSE LICENSE_PUBDOM #define PIL_PLUGINLICENSEURL URL_PUBDOM static const char * RA_PATH = HB_RA_DIR; static const char meta_data_template[] = "\n" "\n" "\n" "1.0\n" "\n" "%s" "\n" "%s\n" "\n" "\n" "\n" "This argument will be passed as the first argument to the " "heartbeat resource agent (assuming it supports one)\n" "\n" "argv[1]\n" "\n" "\n" "\n" "\n" "This argument will be passed as the second argument to the " "heartbeat resource agent (assuming it supports one)\n" "\n" "argv[2]\n" "\n" "\n" "\n" "\n" "This argument will be passed as the third argument to the " "heartbeat resource agent (assuming it supports one)\n" "\n" "argv[3]\n" "\n" "\n" "\n" "\n" "This argument will be passed as the fourth argument to the " "heartbeat resource agent (assuming it supports one)\n" "\n" "argv[4]\n" "\n" "\n" "\n" "\n" "This argument will be passed as the fifth argument to the " "heartbeat resource agent (assuming it supports one)\n" "\n" "argv[5]\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n"; /* The begin of exported function list */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params); static uniform_ret_execra_t map_ra_retvalue(int ret_execra , const char * op_type, const char * std_output); static int get_resource_list(GList ** rsc_info); static char* get_resource_meta(const char* rsc_type, const char* provider); static int get_provider_list(const char* ra_type, GList ** providers); /* The end of exported function list */ /* The begin of internal used function & data list */ #define HADEBUGVAL "HA_DEBUG" #define MAX_PARAMETER_NUM 40 typedef char * RA_ARGV[MAX_PARAMETER_NUM]; const int MAX_LENGTH_OF_RSCNAME = 40, MAX_LENGTH_OF_OPNAME = 40; static int prepare_cmd_parameters(const char * rsc_type, const char * op_type, GHashTable * params, RA_ARGV params_argv); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, map_ra_retvalue, get_resource_list, get_provider_list, get_resource_meta }; PIL_PLUGIN_BOILERPLATE2("1.0", Debug) static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static void* OurImports; static void* interfprivate; static int idebuglevel = 0; /* * Our plugin initialization and registration function * It gets called when the plugin gets loaded. */ PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); PIL_rc PIL_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); if (getenv(HADEBUGVAL) != NULL && atoi(getenv(HADEBUGVAL)) > 0 ) { idebuglevel = atoi(getenv(HADEBUGVAL)); cl_log(LOG_DEBUG, "LRM debug level set to %d", idebuglevel); } /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, NULL, &OurInterface, &OurImports, interfprivate); } /* * Real work starts here ;-) */ static int execra( const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params) { RA_ARGV params_argv; char ra_pathname[RA_MAX_NAME_LENGTH]; uniform_ret_execra_t exit_value; GString * debug_info; char * optype_tmp = NULL; int index_tmp = 0; /* How to generate the meta-data? There is nearly no value * information in meta-data build up in current way. * Should directly add meta-data to the script itself? */ if ( 0 == STRNCMP_CONST(op_type, "meta-data") ) { printf("%s", get_resource_meta(rsc_type, provider)); exit(0); } /* To simulate the 'monitor' operation with 'status'. * Now suppose there is no 'monitor' operation for heartbeat scripts. */ if ( 0 == STRNCMP_CONST(op_type, "monitor") ) { optype_tmp = g_strdup("status"); } else { optype_tmp = g_strdup(op_type); } /* Prepare the call parameter */ if (0 > prepare_cmd_parameters(rsc_type, optype_tmp, params, params_argv)) { cl_log(LOG_ERR, "HB RA: Error of preparing parameters"); g_free(optype_tmp); return -1; } g_free(optype_tmp); get_ra_pathname(RA_PATH, rsc_type, NULL, ra_pathname); /* let this log show only high loglevel. */ if (idebuglevel > 1) { debug_info = g_string_new(""); do { g_string_append(debug_info, params_argv[index_tmp]); g_string_append(debug_info, " "); } while (params_argv[++index_tmp] != NULL); debug_info->str[debug_info->len-1] = '\0'; cl_log(LOG_DEBUG, "RA instance %s executing: heartbeat::%s" , rsc_id, debug_info->str); g_string_free(debug_info, TRUE); } execv(ra_pathname, params_argv); cl_perror("(%s:%s:%d) execv failed for %s" , __FILE__, __FUNCTION__, __LINE__, ra_pathname); switch (errno) { case ENOENT: /* No such file or directory */ case EISDIR: /* Is a directory */ - exit_value = EXECRA_NO_RA; + exit_value = EXECRA_NOT_INSTALLED; break; default: exit_value = EXECRA_EXEC_UNKNOWN_ERROR; } exit(exit_value); } static int prepare_cmd_parameters(const char * rsc_type, const char * op_type, GHashTable * params_ht, RA_ARGV params_argv) { int tmp_len, index; int ht_size = 0; int param_num = 0; char buf_tmp[20]; void * value_tmp; if (params_ht) { ht_size = g_hash_table_size(params_ht); } if ( ht_size+3 > MAX_PARAMETER_NUM ) { cl_log(LOG_ERR, "Too many parameters"); return -1; } /* Now suppose the parameter format stored in Hashtabe is as like as * key="1", value="-Wl,soname=test" * Moreover, the key is supposed as a string transfered from an integer. * It may be changed in the future. */ /* Notice: if ht_size==0, no actual arguments except op_type */ for (index = 1; index <= ht_size; index++ ) { snprintf(buf_tmp, sizeof(buf_tmp), "%d", index); value_tmp = g_hash_table_lookup(params_ht, buf_tmp); /* suppose the key is consecutive */ if ( value_tmp == NULL ) { /* cl_log(LOG_WARNING, "Parameter ordering error in"\ "prepare_cmd_parameters, raexeclsb.c"); cl_log(LOG_WARNING, "search key=%s.", buf_tmp); */ continue; } param_num ++; params_argv[param_num] = g_strdup((char *)value_tmp); } tmp_len = strnlen(rsc_type, MAX_LENGTH_OF_RSCNAME); params_argv[0] = g_strndup(rsc_type, tmp_len); /* Add operation code as the last argument */ tmp_len = strnlen(op_type, MAX_LENGTH_OF_OPNAME); params_argv[param_num+1] = g_strndup(op_type, tmp_len); /* Add the teminating NULL pointer */ params_argv[param_num+2] = NULL; return 0; } static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) { /* Now there is no formal related specification for Heartbeat RA * scripts. Temporarily deal as LSB init script. */ /* Except op_type equals 'status', the UNIFORM_RET_EXECRA is compatible with LSB standard. */ const char * stop_pattern1 = "*stopped*", * stop_pattern2 = "*not*running*", * running_pattern1 = "*running*", * running_pattern2 = "*OK*"; const char * lower_std_output = NULL; + if(ret_execra == EXECRA_NOT_INSTALLED) { + return ret_execra; + } + if ( 0 == STRNCMP_CONST(op_type, "status") || 0 == STRNCMP_CONST(op_type, "monitor")) { if (std_output == NULL ) { cl_log(LOG_WARNING, "No status output from the (hb) resource agent."); return EXECRA_NOT_RUNNING; }else if (idebuglevel) { cl_log(LOG_DEBUG, "RA output was: [%s]", std_output); } lower_std_output = g_ascii_strdown(std_output, -1); if ( TRUE == g_pattern_match_simple(stop_pattern1 , lower_std_output) || TRUE == g_pattern_match_simple(stop_pattern2 , lower_std_output) ) { if (idebuglevel) { cl_log(LOG_DEBUG , "RA output [%s] matched stopped pattern" " [%s] or [%s]" , std_output , stop_pattern1 , stop_pattern2); } return EXECRA_NOT_RUNNING; /* stopped */ } if ( TRUE == g_pattern_match_simple(running_pattern1 , lower_std_output) || TRUE == g_pattern_match_simple(running_pattern2 , std_output) ) { if (idebuglevel) { cl_log(LOG_DEBUG , "RA output [%s] matched running" " pattern [%s] or [%s]" , std_output, running_pattern1 , running_pattern2); } return EXECRA_OK; /* running */ } /* It didn't say it was running - must be stopped */ cl_log(LOG_DEBUG, "RA output [%s] didn't match any pattern" , std_output); return EXECRA_NOT_RUNNING; /* stopped */ } /* For non-status operation return code */ if (ret_execra < 0) { ret_execra = EXECRA_UNKNOWN_ERROR; } return ret_execra; } static int get_resource_list(GList ** rsc_info) { return get_runnable_list(RA_PATH, rsc_info); } static char* get_resource_meta(const char* rsc_type, const char* provider) { GString * meta_data; meta_data = g_string_new(""); g_string_sprintf( meta_data, meta_data_template, rsc_type , rsc_type, rsc_type); return meta_data->str; } static int get_provider_list(const char* ra_type, GList ** providers) { if ( providers == NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: providers==NULL" , __FUNCTION__, __LINE__); return -2; } if ( *providers != NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: *providers==NULL." "This will cause memory leak." , __FUNCTION__, __LINE__); } /* Now temporarily make it fixed */ *providers = g_list_append(*providers, g_strdup("heartbeat")); return g_list_length(*providers); } diff --git a/lib/plugins/lrm/raexeclsb.c b/lib/plugins/lrm/raexeclsb.c index 4128e7c25c..7dfd855b4e 100644 --- a/lib/plugins/lrm/raexeclsb.c +++ b/lib/plugins/lrm/raexeclsb.c @@ -1,606 +1,611 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 software 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 * General Public License for more details. * * You should have received a copy of the GNU 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 * * File: raexeclsb.c * Author: Sun Jiang Dong * Copyright (c) 2004 International Business Machines * * This code implements the Resource Agent Plugin Module for LSB style. * It's a part of Local Resource Manager. Currently it's used by lrmd only. */ /* * Todo * 1) Use flex&bison to make the analysis functions for lsb compliant comment? * 2) Support multiple paths which contain lsb compliant RAs. * 3) Optional and additional actions analysis? */ #include #include #include #include #include #include #include #include #include #include #include /* Add it for compiling on OSX */ #include #include #include #include #include #define PIL_PLUGINTYPE RA_EXEC_TYPE #define PIL_PLUGIN lsb #define PIL_PLUGINTYPE_S "RAExec" #define PIL_PLUGIN_S "lsb" #define PIL_PLUGINLICENSE LICENSE_PUBDOM #define PIL_PLUGINLICENSEURL URL_PUBDOM /* meta-data template for lsb scripts */ /* Note: As for optional actions -- extracted from lsb standard. * The reload and the try-restart options are optional. Other init script * actions may be defined by the init script. */ #define meta_data_template \ "\n"\ "\n"\ "\n"\ " 1.0\n"\ " \n"\ " %s"\ " \n"\ " %s\n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " \n"\ " %s\n"\ " %s\n"\ " %s\n"\ " %s\n"\ " %s\n"\ " %s\n"\ " %s\n"\ " \n"\ "\n" /* The keywords for lsb-compliant comment */ #define LSB_INITSCRIPT_INFOBEGIN_TAG "### BEGIN INIT INFO" #define LSB_INITSCRIPT_INFOEND_TAG "### END INIT INFO" #define PROVIDES "# Provides:" #define REQ_START "# Required-Start:" #define REQ_STOP "# Required-Stop:" #define SHLD_START "# Should-Start:" #define SHLD_STOP "# Should-Stop:" #define DFLT_START "# Default-Start:" #define DFLT_STOP "# Default-Stop:" #define SHORT_DSCR "# Short-Description:" #define DESCRIPTION "# Description:" #define ZAPGDOBJ(m) \ if ( (m) != NULL ) { \ g_free(m); \ (m) = NULL; \ } #define RALSB_GET_VALUE(ptr, keyword) \ if ( (ptr == NULL) & (0 == strncasecmp(buffer, keyword, strlen(keyword))) ) { \ (ptr) = g_strdup(buffer+strlen(keyword)); \ if (*(ptr+strlen(ptr)-1) == '\n') { \ *(ptr+strlen(ptr)-1) = ' '; \ } \ continue; \ } /* * Are there multiple paths? Now according to LSB init scripts, the answer * is 'no', but should be 'yes' for lsb none-init scripts? */ static const char * RA_PATH = LSB_RA_DIR; /* Map to the return code of the 'monitor' operation defined in the OCF RA * specification. */ static const int status_op_exitcode_map[] = { EXECRA_OK, /* LSB_STATUS_OK */ EXECRA_NOT_RUNNING, /* LSB_STATUS_VAR_PID */ EXECRA_NOT_RUNNING, /* LSB_STATUS_VAR_LOCK */ EXECRA_NOT_RUNNING, /* LSB_STATUS_STOPPED */ EXECRA_UNKNOWN_ERROR /* LSB_STATUS_UNKNOWN */ }; /* The begin of exported function list */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params); static uniform_ret_execra_t map_ra_retvalue(int ret_execra , const char * op_type, const char * std_output); static char* get_resource_meta(const char* rsc_type, const char* provider); static int get_resource_list(GList ** rsc_info); static int get_provider_list(const char* ra_type, GList ** providers); /* The end of exported function list */ /* The begin of internal used function & data list */ #define HADEBUGVAL "HA_DEBUG" #define MAX_PARAMETER_NUM 40 const int MAX_LENGTH_OF_RSCNAME = 40, MAX_LENGTH_OF_OPNAME = 40; typedef char * RA_ARGV[MAX_PARAMETER_NUM]; static int prepare_cmd_parameters(const char * rsc_type, const char * op_type, GHashTable * params, RA_ARGV params_argv); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, map_ra_retvalue, get_resource_list, get_provider_list, get_resource_meta }; PIL_PLUGIN_BOILERPLATE2("1.0", Debug) static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static void* OurImports; static void* interfprivate; /* * Our plugin initialization and registration function * It gets called when the plugin gets loaded. */ PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); PIL_rc PIL_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 interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, NULL, &OurInterface, &OurImports, interfprivate); } /* * Real work starts here ;-) */ static int execra( const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params) { uniform_ret_execra_t exit_value; RA_ARGV params_argv; char ra_pathname[RA_MAX_NAME_LENGTH]; GString * debug_info; char * inherit_debuglevel = NULL; char * optype_tmp = NULL; int index_tmp = 0; /* Specially handle the operation "metameta-data". To build up its * output from templet, dummy data and its comment head. */ if ( 0 == STRNCMP_CONST(op_type, "meta-data")) { printf("%s", get_resource_meta(rsc_type, provider)); exit(0); } /* To simulate the 'monitor' operation with 'status'. * Now suppose there is no 'monitor' operation for LSB scripts. */ if (0 == STRNCMP_CONST(op_type, "monitor")) { optype_tmp = g_strdup("status"); } else { optype_tmp = g_strdup(op_type); } /* Prepare the call parameter */ if ( prepare_cmd_parameters(rsc_type, optype_tmp, params, params_argv) != 0) { cl_log(LOG_ERR, "lsb RA: Error of preparing parameters"); g_free(optype_tmp); return -1; } g_free(optype_tmp); get_ra_pathname(RA_PATH, rsc_type, NULL, ra_pathname); /* let this log show only high loglevel. */ inherit_debuglevel = getenv(HADEBUGVAL); if ((inherit_debuglevel != NULL) && (atoi(inherit_debuglevel) > 1)) { debug_info = g_string_new(""); do { g_string_append(debug_info, params_argv[index_tmp]); g_string_append(debug_info, " "); } while (params_argv[++index_tmp] != NULL); debug_info->str[debug_info->len-1] = '\0'; cl_log(LOG_DEBUG, "RA instance %s executing: lsb::%s" , rsc_id, debug_info->str); g_string_free(debug_info, TRUE); } execv(ra_pathname, params_argv); cl_perror("(%s:%s:%d) execv failed for %s" , __FILE__, __FUNCTION__, __LINE__, ra_pathname); switch (errno) { case ENOENT: /* No such file or directory */ /* Fall down */ case EISDIR: /* Is a directory */ - exit_value = EXECRA_NO_RA; + exit_value = EXECRA_NOT_INSTALLED; break; default: exit_value = EXECRA_EXEC_UNKNOWN_ERROR; } exit(exit_value); } static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) { /* Except op_type equals 'status', the UNIFORM_RET_EXECRA is compatible * with the LSB standard. */ if (ret_execra < 0) { return EXECRA_UNKNOWN_ERROR; } + + if(ret_execra == EXECRA_NOT_INSTALLED) { + return ret_execra; + } + if ( 0 == STRNCMP_CONST(op_type, "status") || 0 == STRNCMP_CONST(op_type, "monitor")) { if (ret_execra < DIMOF(status_op_exitcode_map)) { ret_execra = status_op_exitcode_map[ret_execra]; } } return ret_execra; } static int get_resource_list(GList ** rsc_info) { char ra_pathname[RA_MAX_NAME_LENGTH]; FILE * fp; gboolean next_continue, found_begin_tag, is_lsb_script; int rc = 0; GList *cur, *tmp; const size_t BUFLEN = 80; char buffer[BUFLEN]; if ((rc = get_runnable_list(RA_PATH, rsc_info)) <= 0) { return rc; } /* Use the following comment line as the filter patterns to choose * the real LSB-compliant scripts. * "### BEGIN INIT INFO" and "### END INIT INFO" */ cur = g_list_first(*rsc_info); while ( cur != NULL ) { get_ra_pathname(RA_PATH, cur->data, NULL, ra_pathname); if ( (fp = fopen(ra_pathname, "r")) == NULL ) { tmp = g_list_next(cur); *rsc_info = g_list_remove(*rsc_info, cur->data); g_free(cur->data); cur = tmp; continue; } is_lsb_script = FALSE; next_continue = FALSE; found_begin_tag = FALSE; while (NULL != fgets(buffer, BUFLEN, fp)) { /* Handle the lines over BUFLEN(80) columns, only * the first part is compared. */ if ( next_continue == TRUE ) { continue; } if (strlen(buffer) == BUFLEN ) { next_continue = TRUE; } else { next_continue = FALSE; } /* Shorten the search time */ if (buffer[0] != '#' && buffer[0] != ' ' && buffer[0] != '\n') { break; /* donnot find */ } if (found_begin_tag == TRUE && 0 == strncasecmp(buffer , LSB_INITSCRIPT_INFOEND_TAG , strlen(LSB_INITSCRIPT_INFOEND_TAG)) ) { is_lsb_script = TRUE; break; } if (found_begin_tag == FALSE && 0 == strncasecmp(buffer , LSB_INITSCRIPT_INFOBEGIN_TAG , strlen(LSB_INITSCRIPT_INFOBEGIN_TAG)) ) { found_begin_tag = TRUE; } } fclose(fp); tmp = g_list_next(cur); /* * Temporarily remove the filter to the initscript, or many initscripts on * many distros, such as RHEL4 and fedora5, cannot be used by management GUI. * Please refer to the bug * http://www.osdl.org/developer_bugzilla/show_bug.cgi?id=1250 */ #if 0 if ( is_lsb_script != TRUE ) { *rsc_info = g_list_remove(*rsc_info, cur->data); g_free(cur->data); } #endif cur = tmp; } return g_list_length(*rsc_info); } static int prepare_cmd_parameters(const char * rsc_type, const char * op_type, GHashTable * params_ht, RA_ARGV params_argv) { int tmp_len; int ht_size = 0; #if 0 /* Reserve it for possible furture use */ int index; void * value_tmp = NULL; char buf_tmp[20]; #endif if (params_ht) { ht_size = g_hash_table_size(params_ht); } /* Need 3 additonal spaces for accomodating: * argv[0] = RA_file_name(RA_TYPE) * argv[1] = operation * a terminal NULL */ if ( ht_size+3 > MAX_PARAMETER_NUM ) { cl_log(LOG_ERR, "Too many parameters"); return -1; } tmp_len = strnlen(rsc_type, MAX_LENGTH_OF_RSCNAME); params_argv[0] = g_strndup(rsc_type, tmp_len); /* Add operation code as the first argument */ tmp_len = strnlen(op_type, MAX_LENGTH_OF_OPNAME); params_argv[1] = g_strndup(op_type, tmp_len); /* * No actual arguments needed except op_type. * Add the teminating NULL pointer. */ params_argv[2] = NULL; if ( (ht_size != 0) && (0 != STRNCMP_CONST(op_type, "status")) ) { cl_log(LOG_WARNING, "For LSB init script, no additional " "parameters are needed."); } /* Actually comment the following code, but I still think it may be used * in the future for LSB none-initial scripts, so reserver it. */ #if 0 /* Now suppose the parameter formate stored in Hashtabe is like * key="1", value="-Wl,soname=test" * Moreover, the key is supposed as a string transfered from an integer. * It may be changed in the future. */ for (index = 1; index <= ht_size; index++ ) { snprintf(buf_tmp, sizeof(buf_tmp), "%d", index); value_tmp = g_hash_table_lookup(params_ht, buf_tmp); /* suppose the key is consecutive */ if ( value_tmp == NULL ) { cl_log(LOG_ERR, "Parameter ordering error in"\ "prepare_cmd_parameters, raexeclsb.c"); return -1; } params_argv[index+1] = g_strdup((char *)value_tmp); } #endif return 0; } static char* get_resource_meta(const char* rsc_type, const char* provider) { char ra_pathname[RA_MAX_NAME_LENGTH]; FILE * fp; gboolean next_continue; GString * meta_data; const size_t BUFLEN = 132; char buffer[BUFLEN]; char * provides = NULL, * req_start = NULL, * req_stop = NULL, * shld_start = NULL, * shld_stop = NULL, * dflt_start = NULL, * dflt_stop = NULL, * s_dscrpt = NULL; GString * l_dscrpt = NULL; /* * Use the following tags to find the LSb-compliant comment block. * "### BEGIN INIT INFO" and "### END INIT INFO" */ get_ra_pathname(RA_PATH, rsc_type, NULL, ra_pathname); if ( (fp = fopen(ra_pathname, "r")) == NULL ) { cl_log(LOG_ERR, "Failed to open lsb RA %s. No meta-data gotten." , rsc_type); return NULL; } meta_data = g_string_new(""); next_continue = FALSE; /* * Is not stick to the rule that the description should be located in the * comment block between "### BEGIN INIT INFO" and "### END INIT INFO". * Please refer to the bug * http://www.osdl.org/developer_bugzilla/show_bug.cgi?id=1250 */ #if 0 while (NULL != fgets(buffer, BUFLEN, fp)) { /* Handle the lines over BUFLEN(80) columns, only * the first part is compared. */ if ( next_continue == TRUE ) { continue; } if (strlen(buffer) == BUFLEN ) { next_continue = TRUE; } else { next_continue = FALSE; } if ( 0 == strncasecmp(buffer , LSB_INITSCRIPT_INFOBEGIN_TAG , strlen(LSB_INITSCRIPT_INFOBEGIN_TAG)) ) { break; } } #endif /* Enter into the lsb-compliant comment block */ while ( NULL != fgets(buffer, BUFLEN, fp) ) { /* Now suppose each of the following eight arguments contain * only one line */ RALSB_GET_VALUE(provides, PROVIDES) RALSB_GET_VALUE(req_start, REQ_START) RALSB_GET_VALUE(req_stop, REQ_STOP) RALSB_GET_VALUE(shld_start, SHLD_START) RALSB_GET_VALUE(shld_stop, SHLD_STOP) RALSB_GET_VALUE(dflt_start, DFLT_START) RALSB_GET_VALUE(dflt_stop, DFLT_STOP) RALSB_GET_VALUE(s_dscrpt, SHORT_DSCR) /* Long description may cross multiple lines */ if ( (l_dscrpt == NULL) & (0 == strncasecmp(buffer, DESCRIPTION , strlen(DESCRIPTION))) ) { l_dscrpt = g_string_new(buffer+strlen(DESCRIPTION)); /* Between # and keyword, more than one space, or a tab * character, indicates the continuation line. * Extracted from LSB init script standatd */ while ( NULL != fgets(buffer, BUFLEN, fp) ) { if ( (0 == strncmp(buffer, "# ", 3)) || (0 == strncmp(buffer, "#\t", 2)) ) { buffer[0] = ' '; l_dscrpt = g_string_append(l_dscrpt , buffer); } else { fputs(buffer, fp); break; /* Long description ends */ } } continue; } if ( 0 == strncasecmp(buffer, LSB_INITSCRIPT_INFOEND_TAG , strlen(LSB_INITSCRIPT_INFOEND_TAG)) ) { /* Get to the out border of LSB comment block */ break; } if ( buffer[0] != '#' ) { break; /* Out of comment block in the beginning */ } } fclose(fp); g_string_sprintf( meta_data, meta_data_template, rsc_type , (l_dscrpt==NULL)? rsc_type : l_dscrpt->str , (s_dscrpt==NULL)? rsc_type : s_dscrpt , (provides==NULL)? "" : provides , (req_start==NULL)? "" : req_start , (req_stop==NULL)? "" : req_stop , (shld_start==NULL)? "" : shld_start , (shld_stop==NULL)? "" : shld_stop , (dflt_start==NULL)? "" : dflt_start , (dflt_stop==NULL)? "" : dflt_stop ); if ( l_dscrpt != NULL) { g_string_free(l_dscrpt, TRUE); l_dscrpt = NULL; } ZAPGDOBJ(s_dscrpt); ZAPGDOBJ(provides); ZAPGDOBJ(req_start); ZAPGDOBJ(req_stop); ZAPGDOBJ(shld_start); ZAPGDOBJ(shld_stop); ZAPGDOBJ(dflt_start); ZAPGDOBJ(dflt_stop); return meta_data->str; } static int get_provider_list(const char* ra_type, GList ** providers) { if ( providers == NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: providers==NULL" , __FUNCTION__, __LINE__); return -2; } if ( *providers != NULL ) { cl_log(LOG_ERR, "%s:%d: Parameter error: *providers==NULL." "This will cause memory leak." , __FUNCTION__, __LINE__); } /* Now temporarily make it fixed */ *providers = g_list_append(*providers, g_strdup("heartbeat")); return g_list_length(*providers); } diff --git a/lib/plugins/lrm/raexecocf.c b/lib/plugins/lrm/raexecocf.c index 6c7732c3be..32851a849c 100644 --- a/lib/plugins/lrm/raexecocf.c +++ b/lib/plugins/lrm/raexecocf.c @@ -1,493 +1,493 @@ /* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU 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 software 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 * General Public License for more details. * * You should have received a copy of the GNU 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 * * File: raexecocf.c * Author: Sun Jiang Dong * Copyright (c) 2004 International Business Machines * * This code implements the Resource Agent Plugin Module for LSB style. * It's a part of Local Resource Manager. Currently it's used by lrmd only. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Add it for compiling on OSX */ #include # define PIL_PLUGINTYPE RA_EXEC_TYPE # define PIL_PLUGINTYPE_S "RAExec" # define PIL_PLUGINLICENSE LICENSE_PUBDOM # define PIL_PLUGINLICENSEURL URL_PUBDOM # define PIL_PLUGIN ocf # define PIL_PLUGIN_S "ocf" /* * Are there multiple paths? Now according to OCF spec, the answer is 'no'. * But actually or for future? */ static const char * RA_PATH = OCF_RA_DIR; /* The begin of exported function list */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params); static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output); static int get_resource_list(GList ** rsc_info); static char* get_resource_meta(const char* rsc_type, const char* provider); static int get_provider_list(const char* ra_type, GList ** providers); /* The end of exported function list */ /* The begin of internal used function & data list */ #define HADEBUGVAL "HA_DEBUG" static void add_OCF_prefix(GHashTable * params, GHashTable * new_params); static void add_OCF_env_vars(GHashTable * env, const char * rsc_id, const char * rsc_type, const char * provider); static void add_prefix_foreach(gpointer key, gpointer value, gpointer user_data); static void hash_to_str(GHashTable * , GString *); static void hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data); static int raexec_setenv(GHashTable * env_params); static void set_env(gpointer key, gpointer value, gpointer user_data); static gboolean let_remove_eachitem(gpointer key, gpointer value, gpointer user_data); static int get_providers(const char* class_path, const char* op_type, GList ** providers); static void merge_string_list(GList** old, GList* new); static gint compare_str(gconstpointer a, gconstpointer b); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, map_ra_retvalue, get_resource_list, get_provider_list, get_resource_meta }; PIL_PLUGIN_BOILERPLATE2("1.0", Debug) static const PILPluginImports* PluginImports; static PILPlugin* OurPlugin; static PILInterface* OurInterface; static void* OurImports; static void* interfprivate; /* * Our plugin initialization and registration function * It gets called when the plugin gets loaded. */ PIL_rc PIL_PLUGIN_INIT(PILPlugin * us, const PILPluginImports* imports); PIL_rc PIL_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 interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, NULL, &OurInterface, &OurImports, interfprivate); } /* * The function to execute a RA. */ static int execra(const char * rsc_id, const char * rsc_type, const char * provider, const char * op_type, const int timeout, GHashTable * params) { uniform_ret_execra_t exit_value; char ra_pathname[RA_MAX_NAME_LENGTH]; GHashTable * tmp_for_setenv; GString * params_gstring; char * inherit_debuglevel = NULL; get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname); /* Setup environment correctly */ tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal); add_OCF_prefix(params, tmp_for_setenv); add_OCF_env_vars(tmp_for_setenv, rsc_id, rsc_type, provider); raexec_setenv(tmp_for_setenv); g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL); g_hash_table_destroy(tmp_for_setenv); /* let this log show only high loglevel. */ inherit_debuglevel = getenv(HADEBUGVAL); if ((inherit_debuglevel != NULL) && (atoi(inherit_debuglevel) > 1)) { params_gstring = g_string_new(""); hash_to_str(params, params_gstring); cl_log(LOG_DEBUG, "RA instance %s executing: OCF::%s %s. Parameters: " "{%s}", rsc_id, rsc_type, op_type, params_gstring->str); g_string_free(params_gstring, TRUE); } /* execute the RA */ execl(ra_pathname, ra_pathname, op_type, NULL); cl_perror("(%s:%s:%d) execl failed for %s" , __FILE__, __FUNCTION__, __LINE__, ra_pathname); switch (errno) { case ENOENT: /* No such file or directory */ case EISDIR: /* Is a directory */ - exit_value = EXECRA_NO_RA; + exit_value = EXECRA_NOT_INSTALLED; break; default: exit_value = EXECRA_EXEC_UNKNOWN_ERROR; } exit(exit_value); } static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op_type, const char * std_output) { /* Because the UNIFORM_RET_EXECRA is compatible with OCF standard, * no actual mapping except validating, which ensure the return code * will be in the range 0 to 7. Too strict? */ if (ret_execra < 0 || ret_execra > 9) { cl_log(LOG_WARNING, "mapped the invalid return code %d." , ret_execra); ret_execra = EXECRA_UNKNOWN_ERROR; } return ret_execra; } static gint compare_str(gconstpointer a, gconstpointer b) { return strncmp(a,b,RA_MAX_NAME_LENGTH); } static int get_resource_list(GList ** rsc_info) { struct dirent **namelist; GList* item; int file_num; char subdir[FILENAME_MAX+1]; if ( rsc_info == NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list"); return -2; } if ( *rsc_info != NULL ) { cl_log(LOG_ERR, "Parameter error: get_resource_list."\ "will cause memory leak."); *rsc_info = NULL; } file_num = scandir(RA_PATH, &namelist, 0, alphasort); if (file_num < 0) { return -2; } while (file_num--) { GList* ra_subdir = NULL; struct stat prop; if ('.' == namelist[file_num]->d_name[0]) { free(namelist[file_num]); continue; } stat(namelist[file_num]->d_name, &prop); if (S_ISDIR(prop.st_mode)) { free(namelist[file_num]); continue; } snprintf(subdir,FILENAME_MAX,"%s/%s", RA_PATH, namelist[file_num]->d_name); get_runnable_list(subdir,&ra_subdir); merge_string_list(rsc_info,ra_subdir); while (NULL != (item = g_list_first(ra_subdir))) { ra_subdir = g_list_remove_link(ra_subdir, item); g_free(item->data); g_list_free_1(item); } free(namelist[file_num]); } free(namelist); return 0; } static void merge_string_list(GList** old, GList* new) { GList* item = NULL; char* newitem; for( item=g_list_first(new); NULL!=item; item=g_list_next(item)){ if (!g_list_find_custom(*old, item->data,compare_str)){ newitem = g_strndup(item->data,RA_MAX_NAME_LENGTH); *old = g_list_append(*old, newitem); } } } static int get_provider_list(const char* ra_type, GList ** providers) { int ret; ret = get_providers(RA_PATH, ra_type, providers); if (0>ret) { cl_log(LOG_ERR, "scandir failed in OCF RA plugin"); } return ret; } static char* get_resource_meta(const char* rsc_type, const char* provider) { const int BUFF_LEN=4096; int read_len = 0; char buff[BUFF_LEN]; char* data = NULL; GString* g_str_tmp = NULL; char ra_pathname[RA_MAX_NAME_LENGTH]; FILE* file = NULL; GHashTable * tmp_for_setenv; get_ra_pathname(RA_PATH, rsc_type, provider, ra_pathname); strncat(ra_pathname, " meta-data",RA_MAX_NAME_LENGTH-strlen(ra_pathname)-1); tmp_for_setenv = g_hash_table_new(g_str_hash, g_str_equal); add_OCF_env_vars(tmp_for_setenv, "DUMMY_INSTANCE", rsc_type, provider); raexec_setenv(tmp_for_setenv); g_hash_table_foreach_remove(tmp_for_setenv, let_remove_eachitem, NULL); g_hash_table_destroy(tmp_for_setenv); file = popen(ra_pathname, "r"); if (NULL==file) { return NULL; } g_str_tmp = g_string_new(""); while(!feof(file)) { memset(buff, 0, BUFF_LEN); read_len = fread(buff, 1, BUFF_LEN - 1, file); if (0len) { pclose(file); return NULL; } data = (char*)g_new(char, g_str_tmp->len+1); data[0] = data[g_str_tmp->len] = 0; strncpy(data, g_str_tmp->str, g_str_tmp->len); g_string_free(g_str_tmp, TRUE); pclose(file); return data; } static void add_OCF_prefix(GHashTable * env_params, GHashTable * new_env_params) { if (env_params) { g_hash_table_foreach(env_params, add_prefix_foreach, new_env_params); } } static void add_prefix_foreach(gpointer key, gpointer value, gpointer user_data) { const int MAX_LENGTH_OF_ENV = 50; int prefix = STRLEN_CONST("OCF_RESKEY_"); GHashTable * new_hashtable = (GHashTable *) user_data; char * newkey; int keylen = strnlen((char*)key, MAX_LENGTH_OF_ENV-prefix)+prefix+1; newkey = g_new(gchar, keylen); strncpy(newkey, "OCF_RESKEY_", keylen); strncat(newkey, key, keylen-strlen(newkey)-1); g_hash_table_insert(new_hashtable, (gpointer)newkey, g_strdup(value)); } static void hash_to_str(GHashTable * params , GString * str) { if (params) { g_hash_table_foreach(params, hash_to_str_foreach, str); } } static void hash_to_str_foreach(gpointer key, gpointer value, gpointer user_data) { char buffer_tmp[60]; GString * str = (GString *)user_data; snprintf(buffer_tmp, 60, "%s=%s ", (char *)key, (char *)value); str = g_string_append(str, buffer_tmp); } static gboolean let_remove_eachitem(gpointer key, gpointer value, gpointer user_data) { g_free(key); g_free(value); return TRUE; } static int raexec_setenv(GHashTable * env_params) { if (env_params) { g_hash_table_foreach(env_params, set_env, NULL); } return 0; } static void set_env(gpointer key, gpointer value, gpointer user_data) { if (setenv(key, value, 1) != 0) { cl_log(LOG_ERR, "setenv failed in raexecocf."); } } static int get_providers(const char* class_path, const char* ra_type, GList ** providers) { struct dirent **namelist; int file_num; if ( providers == NULL ) { cl_log(LOG_ERR, "Parameter error: get_providers"); return -2; } if ( *providers != NULL ) { cl_log(LOG_ERR, "Parameter error: get_providers."\ "will cause memory leak."); *providers = NULL; } file_num = scandir(class_path, &namelist, 0, alphasort); if (file_num < 0) { return -2; }else{ char tmp_buffer[FILENAME_MAX+1]; struct stat prop; while (file_num--) { if ('.' == namelist[file_num]->d_name[0]) { free(namelist[file_num]); continue; } snprintf(tmp_buffer,FILENAME_MAX,"%s/%s", class_path, namelist[file_num]->d_name); stat(tmp_buffer, &prop); if (!S_ISDIR(prop.st_mode)) { free(namelist[file_num]); continue; } snprintf(tmp_buffer,FILENAME_MAX,"%s/%s/%s", class_path, namelist[file_num]->d_name, ra_type); if ( filtered(tmp_buffer) == TRUE ) { *providers = g_list_append(*providers, g_strdup(namelist[file_num]->d_name)); } free(namelist[file_num]); } free(namelist); } return g_list_length(*providers); } static void add_OCF_env_vars(GHashTable * env, const char * rsc_id, const char * rsc_type, const char * provider) { if ( env == NULL ) { cl_log(LOG_WARNING, "env should not be a NULL pointer."); return; } g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MAJOR"), g_strdup("1")); g_hash_table_insert(env, g_strdup("OCF_RA_VERSION_MINOR"), g_strdup("0")); g_hash_table_insert(env, g_strdup("OCF_ROOT"), g_strdup(OCF_ROOT_DIR)); if ( rsc_id != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_INSTANCE"), g_strdup(rsc_id)); } /* Currently the rsc_type=="the filename of the RA script/executable", * It seems always correct even in the furture. ;-) */ if ( rsc_type != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_TYPE"), g_strdup(rsc_type)); } /* Notes: this is not added to specification yet. Sept 10,2004 */ if ( provider != NULL ) { g_hash_table_insert(env, g_strdup("OCF_RESOURCE_PROVIDER"), g_strdup(provider)); } }