diff --git a/lib/plugins/lrm/raexechb.c b/lib/plugins/lrm/raexechb.c index 2695c42b83..0b4ac36653 100644 --- a/lib/plugins/lrm/raexechb.c +++ b/lib/plugins/lrm/raexechb.c @@ -1,399 +1,313 @@ /* * 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 #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 = "/etc/ha.d/resource.d/"; /* The begin of exported function list */ static int execra(const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, - gboolean need_metadata, - int * call_key); + GHashTable * env_params); -static int post_query_result(int exec_key, int * result, char ** meta_data); +static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op); +static int get_resource_list(GList ** rsc_info); /* The end of exported function list */ /* The begin of internal used function & data list */ #define MAX_PARAMETER_NUM 40 typedef char * RA_ARGV[MAX_PARAMETER_NUM]; -static GHashTable * post_query_ops = NULL; static int prepare_cmd_parameters(const char * ra_name, const char * op, GHashTable * params, RA_ARGV params_argv); static void params_hash_to_argv(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 int fork_and_execra(const char * ra_name, const char * op, - RA_ARGV params_arg, GHashTable * env_params, - gboolean need_metadata); -static int read_pipe(int fd, char ** meta_data); -static int * g_intdup(gint value); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, - post_query_result + map_ra_retvalue, + get_resource_list }; /* * The following two functions are only exported to the plugin infrastructure. */ /* * raexec_closepi is called as part of shutting down the plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */ static void raexec_closepi(PILPlugin *pi) { - if ( post_query_ops != NULL ) { - g_hash_table_destroy(post_query_ops); - } } /* * raexec_close_intf called as part of shutting down the md5 HBauth interface. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the md5 implementation, here's our chance * to clean it up. */ static PIL_rc raexec_closeintf(PILInterface *pi, void *pd) { return PIL_OK; } PIL_PLUGIN_BOILERPLATE("1.0", Debug, raexec_closepi); 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); - post_query_ops = g_hash_table_new(g_int_hash, g_int_equal); - /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, raexec_closeintf, &OurInterface, &OurImports, interfprivate); } /* * Real work starts here ;-) */ static int -execra( const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, gboolean need_metadata, int * call_key) +execra( const char * ra_name, const char * op, + GHashTable * cmd_params, GHashTable * env_params ) { RA_ARGV params_argv; + uniform_ret_execra_t exit_value; + char *ra_name_dup, *base_name; + GString * ra_dirname; cl_log(LOG_DEBUG, "To execute a RA %s.", ra_name); /* Prepare the call parameter */ if (0 > prepare_cmd_parameters(ra_name, op, cmd_params, params_argv)) { cl_log(LOG_ERR, "HB RA: Error of preparing parameters"); return -1; } - /* Fork a child and execute the RA */ - *call_key = fork_and_execra(ra_name, op, params_argv, - env_params, need_metadata); - - if (*call_key <= 0) { - return -1; - } - else { - return 0; /* return ok */ - } -} - -static int -post_query_result(int exec_key, int * result, char ** meta_data) -{ - int ret; - gpointer org_key, org_value; - gboolean found = FALSE; - - if ( post_query_ops == NULL ) { - return -1; - } - - found = g_hash_table_lookup_extended(post_query_ops, - &exec_key, &org_key, &org_value); - if ( !found ) { - cl_log(LOG_ERR,"No this child %d need post query.", exec_key); - return -1; + ra_dirname = g_string_new(ra_name); + ra_name_dup = strndup(ra_name, RA_MAX_DIRNAME_LENGTH); + base_name = basename(ra_name_dup); + /* + * If ra_name only contains basename, then append RA_PATH. + * If ra_name is a pathname, then don't deal with it. + */ + if ( strncmp(ra_name, base_name, RA_MAX_BASENAME_LENGTH) == 0 ) { + g_string_insert(ra_dirname, 0, RA_PATH); } + free(ra_name_dup); - ret = waitpid(exec_key, result, WNOHANG); - if ( ret == 0 ) { - cl_log(LOG_DEBUG, "process %d don't exit yet.", exec_key); - /* return at once to avoid remove item in 'post_query_ops' */ - return 0; + /* For heartbeat scripts, no definite specification for parameters + * Not set calling parameters + */ + raexec_setenv(env_params); + if ( execv(ra_name, params_argv) < 0 ) { + cl_log(LOG_ERR, "execl error when to execute RA %s.", ra_name); } - if ( ret == -1 ) { - cl_log(LOG_ERR, "error when fetching %d exit status.", - exec_key); - } + switch (errno) { + case ENOENT: /* No such file or directory */ + case EISDIR: /* Is a directory */ + exit_value = EXECRA_NO_RA; + break; - if ((ret > 0) && (*(int*)org_value > 0) && ( meta_data != NULL )) { - read_pipe(*(int*)org_value, meta_data); - } + default: + exit_value = EXECRA_EXEC_UNKNOWN_ERROR; + } - g_free(org_key); - g_free(org_value); - g_hash_table_remove(post_query_ops, &exec_key); - - return ret; + cl_log(LOG_ERR, "execl error when to execute RA %s.", ra_name); + exit(exit_value); } static int prepare_cmd_parameters(const char * raname, const char * op, GHashTable * params_ht, RA_ARGV params_argv) { /* For heartbeat scripts, no corresponding definite specification * Maybe not need this function? */ - int ht_size = 0; int tmp_len; + int ht_size = 0; if (params_ht) { g_hash_table_size(params_ht); } if ( ht_size+3 > MAX_PARAMETER_NUM ) { cl_log(LOG_ERR, "Too many parameters"); return -1; } tmp_len = strnlen(raname, 160) + 1; params_argv[0] = g_new(char, tmp_len); strncpy(params_argv[0], raname, tmp_len); tmp_len = strnlen(op, 160) + 1; params_argv[1] = g_new(char, tmp_len); strncpy(params_argv[1], op, tmp_len); params_argv[ht_size+2] = NULL; if (params_ht) { g_hash_table_foreach(params_ht, params_hash_to_argv, ¶ms_argv); } return 0; } +static uniform_ret_execra_t +map_ra_retvalue(int ret_execra, const char * op) +{ + /* Now there is no related specification for Heartbeat standard. + * Temporarily deal as below. + */ + return ret_execra; +} + +static int +get_resource_list(GList ** rsc_info) +{ + struct dirent **namelist; + int file_num; + + 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) { + cl_log(LOG_ERR, "scandir failed in OCF RA plugin"); + return -2; + } else + { + while (file_num--) { + rsc_info_t * rsc_info_tmp; + if (*(namelist[file_num]->d_name) != '.') { + rsc_info_tmp = g_new(rsc_info_t, 1); + rsc_info_tmp->rsc_type = + g_strdup(namelist[file_num]->d_name); + /* + * Since the version definition isn't cleat yet, + * the version is setted 1.0. + */ + rsc_info_tmp->version = g_strdup("1.0"); + } + free(namelist[file_num]); + } + free(namelist); + } + return 0; +} + static void params_hash_to_argv(gpointer key, gpointer value, gpointer user_data) { int param_index; RA_ARGV * ra_argv = (RA_ARGV *) user_data; if (ra_argv == NULL ) { return; } /* the parameter index start from 1 */ /* and start from 2 in argv array */ param_index = atoi( (char*) key ); (*ra_argv)[param_index + 1] = g_new(char, 21); *((*ra_argv)[param_index + 1] + 20) = '\0'; strncpy((*ra_argv)[param_index + 1], (char*)value, strnlen((char*)value, 20)); } -/* Possible bug for pipe using ?? */ -static int -fork_and_execra(const char * ra_name, const char * op, RA_ARGV cmd_argv, - GHashTable * env_params, gboolean need_metadata) -{ - int cpid; - int fd[2]; - - cl_log(LOG_DEBUG, "Will to execute RA %s.", ra_name); - if (need_metadata == TRUE) - if ( pipe(fd) < 0 ) { - cl_log(LOG_ERR,"pipe create error when to execute %s.", - ra_name); - return -1; - } - - if ( (cpid=fork()) < 0 ) { - cl_log(LOG_ERR, "Fork failed when to execute %s.", ra_name); - return -1; - } - - if ( cpid > 0 ) { - /* In parent process */ - /* close write fd */ - if ( need_metadata == TRUE ) { - close(fd[1]); - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(fd[0])); - } - else - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(0)); - return cpid; - } else { - /* in child process */ - /* close read fd */ - cl_log(LOG_DEBUG, "In forked child %d.", getpid()); - - if ( need_metadata == TRUE ) { - close(fd[0]); - if ( fd[1] != STDOUT_FILENO ) { - if (dup2(fd[1], STDOUT_FILENO)!=STDOUT_FILENO) { - cl_log(LOG_ERR,"dup2 error when to "\ - "execute RA."); - exit(-1); - } - } - close(fd[1]); - } - - /* For heartbeat scripts, no definite specification for parameters - * Not set calling parameters - */ - raexec_setenv(env_params); - if ( execv(ra_name, cmd_argv) < 0 ) { - cl_log(LOG_ERR, "execl error when to execute RA %s.", - ra_name); - } - - exit(-1); - } -} - -static int -read_pipe(int fd, char ** meta_data) -{ - const int BUFFLEN = 81; - char buffer[BUFFLEN]; - int readlen; - GString * gstr_tmp; - - *meta_data = NULL; - gstr_tmp = g_string_new(""); - do { - memset(buffer, 0, BUFFLEN); - readlen = read(fd, buffer, BUFFLEN - 1); - if ( readlen > 0 ) { - g_string_append(gstr_tmp, buffer); - } - } while (readlen == BUFFLEN - 1); - close(fd); - - if (readlen < 0) { - cl_log(LOG_ERR, "read pipe error when execute RA."); - return -1; - } - if ( gstr_tmp->len == 0 ) { - cl_log(LOG_INFO, "read 0 byte from this pipe when execute RA."); - return 0; - } - - *meta_data = malloc(gstr_tmp->len + 1); - if ( *meta_data == NULL ) { - cl_log(LOG_ERR, "malloc error in read_pipe."); - return -1; - } - - (*meta_data)[0] = '\0'; - (*meta_data)[gstr_tmp->len] = '\0'; - strncpy(*meta_data, gstr_tmp->str, gstr_tmp->len); - g_string_free(gstr_tmp, TRUE); - return 0; -} - static int raexec_setenv(GHashTable * env_params) { /* * For heartbeat scripts, no definite specification for environment * parameters. Maybe no need to this function? */ if (env_params) { g_hash_table_foreach(env_params, set_env, NULL); } /* Need to free the env_params ? */ return 0; } static void set_env(gpointer key, gpointer value, gpointer user_data) { setenv((const char *)key, (const char *)value, 1); /*Need to free the memory to which key and value point?*/ } - -static int * -g_intdup(gint value) -{ - gint * tmp; - tmp = g_new(gint,1); - *tmp = value; - return tmp; -} diff --git a/lib/plugins/lrm/raexeclsb.c b/lib/plugins/lrm/raexeclsb.c index 91aa73a4b4..cf8462c8d6 100644 --- a/lib/plugins/lrm/raexeclsb.c +++ b/lib/plugins/lrm/raexeclsb.c @@ -1,399 +1,322 @@ /* * 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. */ #include #include #include #include #include #include #include +#include +#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 +/* + * 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 = "/lib/lsb/init-functions/"; +static const int status_op_exitcode_map[] = { 0, 11, 12, 13, 14 }; /* The begin of exported function list */ static int execra(const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, - gboolean need_metadata, - int * call_key); + GHashTable * env_params); -static int post_query_result(int exec_key, int * result, char ** meta_data); +static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op); +static int get_resource_list(GList ** rsc_info); /* The end of exported function list */ /* The begin of internal used function & data list */ #define MAX_PARAMETER_NUM 40 typedef char * RA_ARGV[MAX_PARAMETER_NUM]; -static GHashTable * post_query_ops = NULL; static int prepare_cmd_parameters(const char * raname, const char * op, GHashTable * params, RA_ARGV params_argv); static void params_hash_to_argv(gpointer key, gpointer value, gpointer user_data); static int raexec_setenv(GHashTable * env_params); -static int fork_and_execra(const char * ra_name, const char * op, - RA_ARGV ra_argv, GHashTable * env_params, - gboolean need_metadata); -static int read_pipe(int fd, char ** meta_data); -static int * g_intdup(gint value); static void set_env(gpointer key, gpointer value, gpointer user_data); /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, - post_query_result + map_ra_retvalue, + get_resource_list }; /* * The following two functions are only exported to the plugin infrastructure. */ /* * raexec_closepi is called as part of shutting down the plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */ static void raexec_closepi(PILPlugin *pi) { - if ( post_query_ops != NULL ) { - g_hash_table_destroy(post_query_ops); - } } /* * raexec_close_intf called as part of shutting down the md5 HBauth interface. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the md5 implementation, here's our chance * to clean it up. */ static PIL_rc raexec_closeintf(PILInterface *pi, void *pd) { return PIL_OK; } PIL_PLUGIN_BOILERPLATE("1.0", Debug, raexec_closepi); 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); - post_query_ops = g_hash_table_new(g_int_hash, g_int_equal); - /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, raexec_closeintf, &OurInterface, &OurImports, interfprivate); } /* * Real work starts here ;-) */ static int -execra( const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, gboolean need_metadata, int * call_key) +execra( const char * ra_name, const char * op, + GHashTable * cmd_params, GHashTable * env_params ) { + uniform_ret_execra_t exit_value; RA_ARGV params_argv; + char *ra_name_dup, *base_name; + GString * ra_dirname; cl_log(LOG_DEBUG, "To execute a RA %s.", ra_name); /* Prepare the call parameter */ if (0 > prepare_cmd_parameters(ra_name, op, cmd_params, params_argv)) { cl_log(LOG_ERR, "lsb RA: Error of preparing parameters"); return -1; } + + ra_dirname = g_string_new(ra_name); + ra_name_dup = strndup(ra_name, RA_MAX_DIRNAME_LENGTH); + base_name = basename(ra_name_dup); + /* + * If ra_name only contains basename, then append RA_PATH. + * If ra_name is a pathname, then don't deal with it. + */ + if ( strncmp(ra_name, base_name, RA_MAX_BASENAME_LENGTH) == 0 ) { + g_string_insert(ra_dirname, 0, RA_PATH); + } + free(ra_name_dup); + + raexec_setenv(env_params); + execv(ra_dirname->str, params_argv); - /* Fork a child and execute the RA */ - *call_key = fork_and_execra(ra_name, op, params_argv, env_params, - need_metadata); + switch (errno) { + case ENOENT: /* No such file or directory */ + case EISDIR: /* Is a directory */ + exit_value = EXECRA_NO_RA; + break; - if (*call_key <= 0) { - return -1; - } - else { - return 0; /* return ok */ - } + default: + exit_value = EXECRA_EXEC_UNKNOWN_ERROR; + } + + cl_log(LOG_ERR, "execl error when to execute RA %s.", ra_name); + exit(exit_value); } -static int -post_query_result(int exec_key, int * result, char ** meta_data) +static uniform_ret_execra_t +map_ra_retvalue(int ret_execra, const char * op) { - int ret; - gpointer org_key, org_value; - gboolean found = FALSE; - - if ( post_query_ops == NULL ) { - return -1; + /* Except op equals 'status', the UNIFORM_RET_EXECRA is compatible + with LSB standard. + */ + if ( strncmp(op, "status", 6) == 0 ) { + if (ret_execra < 0 || ret_execra > 4 ) { + ret_execra = 4; + } + return status_op_exitcode_map[ret_execra]; + } else + { + return ret_execra; } +} - found = g_hash_table_lookup_extended(post_query_ops, - &exec_key, &org_key, &org_value); - if ( !found ) { - cl_log(LOG_ERR,"No this child %d need post query.", exec_key); - return -1; - } - ret = waitpid(exec_key, result, WNOHANG); - if ( ret == 0 ) { - cl_log(LOG_DEBUG, "process %d don't exit yet.", exec_key); - /* return at once to avoid remove item in 'post_query_ops' */ - return 0; - } +static int +get_resource_list(GList ** rsc_info) +{ + struct dirent **namelist; + int file_num; - if ( ret == -1 ) { - cl_log(LOG_ERR, "error when fetching %d exit status.", - exec_key); + if ( rsc_info == NULL ) { + cl_log(LOG_ERR, "Parameter error: get_resource_list"); + return -2; } - if ((ret > 0) && (*(int*)org_value > 0) && ( meta_data != NULL )) { - read_pipe(*(int*)org_value, meta_data); + if ( *rsc_info != NULL ) { + cl_log(LOG_ERR, "Parameter error: get_resource_list."\ + "will cause memory leak."); + *rsc_info = NULL; } - - g_free(org_key); - g_free(org_value); - g_hash_table_remove(post_query_ops, &exec_key); - - return ret; + + file_num = scandir(RA_PATH, &namelist, 0, alphasort); + if (file_num < 0) { + cl_log(LOG_ERR, "scandir failed in OCF RA plugin"); + return -2; + } else + { + while (file_num--) { + rsc_info_t * rsc_info_tmp; + if (*(namelist[file_num]->d_name) != '.') { + rsc_info_tmp = g_new(rsc_info_t, 1); + rsc_info_tmp->rsc_type = + g_strdup(namelist[file_num]->d_name); + /* + * Since the version definition isn't cleat yet, + * the version is setted 1.0. + */ + rsc_info_tmp->version = g_strdup("1.0"); + } + free(namelist[file_num]); + } + free(namelist); + } + return 0; } static int prepare_cmd_parameters(const char * raname, const char * op, GHashTable * params_ht, RA_ARGV params_argv) { /* For lsb init scripts, no corresponding definite specification * But for lsb none-init scripts, maybe need it. */ - int ht_size = 0; int tmp_len; - + int ht_size = 0; 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; } tmp_len = strnlen(raname, 160) + 1; params_argv[0] = g_new(gchar, tmp_len); strncpy(params_argv[0], raname, tmp_len); tmp_len = strnlen(op, 160) + 1; params_argv[1] = g_new(gchar, tmp_len); strncpy(params_argv[1], op, tmp_len); params_argv[ht_size+2] = NULL; if (params_ht) { g_hash_table_foreach(params_ht, params_hash_to_argv, params_argv); } return 0; } static void params_hash_to_argv(gpointer key, gpointer value, gpointer user_data) { - int param_index; RA_ARGV * ra_argv = user_data; + int param_index; + if (user_data == NULL) { + return; + } if (*ra_argv == NULL ) { return; } /* the parameter index start from 1 */ /* and start from 2 in argv array */ param_index = atoi((char *)key); (*ra_argv)[param_index + 1] = g_new(gchar, 21); *((*ra_argv)[param_index + 1] + 20) = '\0'; strncpy((*ra_argv)[param_index +1], (char*)value, strnlen((char*)value, 20)); } static int raexec_setenv(GHashTable * env_params) { /* For lsb init scripts, no corresponding definite specification * But for lsb none-init scripts, maybe need it. */ 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) { setenv((const char *)key, (const char *)value, 1); /*Need to free the memory to which key and value point?*/ } - -/* Possible bug for pipe using ?? */ -static int -fork_and_execra(const char * ra_name, const char * op, RA_ARGV ra_argv, - GHashTable * env_params, gboolean need_metadata) -{ - int cpid; - int fd[2]; - - cl_log(LOG_DEBUG, "Will to execute RA %s.", ra_name); - if (need_metadata == TRUE) { - if ( pipe(fd) < 0 ) { - cl_log(LOG_ERR,"pipe create error when to execute %s.", - ra_name); - return -1; - } - } - - if ( (cpid=fork()) < 0 ) { - cl_log(LOG_ERR, "Fork failed when to execute %s.", ra_name); - return -1; - } - - if ( cpid > 0 ) { - /* In parent process */ - /* close write fd */ - if ( need_metadata == TRUE ) { - close(fd[1]); - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(fd[0])); - } else { - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(0)); - } - return cpid; - } else { - /* in child process */ - /* close read fd */ - cl_log(LOG_DEBUG, "In forked child %d.", getpid()); - - if ( need_metadata == TRUE ) { - close(fd[0]); - if ( fd[1] != STDOUT_FILENO ) { - if (dup2(fd[1], STDOUT_FILENO)!=STDOUT_FILENO) { - cl_log(LOG_ERR,"dup2 error when to "\ - "execute RA."); - exit(-1); - } - } - close(fd[1]); - } - - /* For lsb init scripts, no corresponding definite specification - * Not set calling parameterscl. But for lsb none-init scripts, - * should need - */ - raexec_setenv(env_params); - if ( execv(ra_name, ra_argv) < 0 ) { - cl_log(LOG_ERR, "execl error when to execute RA %s.", - ra_name); - } - exit(-1); - } -} - -static int -read_pipe(int fd, char ** meta_data) -{ - const int BUFFLEN = 81; - char buffer[BUFFLEN]; - int readlen; - GString * gstr_tmp; - - *meta_data = NULL; - gstr_tmp = g_string_new(""); - do { - memset(buffer, 0, BUFFLEN); - readlen = read(fd, buffer, BUFFLEN - 1); - if ( readlen > 0 ) { - g_string_append(gstr_tmp, buffer); - } - } while (readlen == BUFFLEN - 1); - close(fd); - - if (readlen < 0) { - cl_log(LOG_ERR, "read pipe error when execute RA."); - return -1; - } - if ( gstr_tmp->len == 0 ) { - cl_log(LOG_INFO, "read 0 byte from this pipe when execute RA."); - return 0; - } - - *meta_data = malloc(gstr_tmp->len + 1); - if ( *meta_data == NULL ) { - cl_log(LOG_ERR, "malloc error in read_pipe."); - return -1; - } - - (*meta_data)[0] = '\0'; - (*meta_data)[gstr_tmp->len] = '\0'; - strncpy(*meta_data, gstr_tmp->str, gstr_tmp->len); - g_string_free(gstr_tmp, TRUE); - return 0; -} - -static int * -g_intdup(gint value) -{ - gint * tmp; - - tmp = g_new(gint, 1); - *tmp = value; - return tmp; -} diff --git a/lib/plugins/lrm/raexecocf.c b/lib/plugins/lrm/raexecocf.c index 79a4f13900..89b31c2d05 100644 --- a/lib/plugins/lrm/raexecocf.c +++ b/lib/plugins/lrm/raexecocf.c @@ -1,331 +1,252 @@ /* * 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 #define PIL_PLUGINTYPE RA_EXEC_TYPE #define PIL_PLUGIN ocf #define PIL_PLUGINTYPE_S "RAExec" #define PIL_PLUGIN_S "ocf" #define PIL_PLUGINLICENSE LICENSE_PUBDOM #define PIL_PLUGINLICENSEURL URL_PUBDOM +/* + * Are there multiple paths? Now according to OCF spec, the answer is 'no'. + * But actually or for future? + */ +static const char * RA_PATH = "/usr/ocf/resource.d/"; /* The begin of exported function list */ static int execra(const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, - gboolean need_metadata, - int * call_key); + GHashTable * env_params); -static int post_query_result(int exec_key, int * result, char ** meta_data); +static uniform_ret_execra_t map_ra_retvalue(int ret_execra, const char * op); + +static int get_resource_list(GList ** rsc_info); /* The end of exported function list */ /* The begin of internal used function & data list */ static int raexec_setenv(GHashTable * env_params); -static int fork_and_execra(const char * ra_name, const char * op, - const char * cmd_params, GHashTable * env_params, - gboolean need_metadata); -static int read_pipe(int fd, char ** meta_data); -static int * g_intdup(gint value); static void set_env(gpointer key, gpointer value, gpointer user_data); - -static GHashTable * post_query_ops = NULL; /* The end of internal function & data list */ /* Rource agent execution plugin operations */ static struct RAExecOps raops = { execra, - post_query_result + map_ra_retvalue, + get_resource_list }; /* * The following two functions are only exported to the plugin infrastructure. */ /* * raexec_closepi is called as part of shutting down the plugin. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the plugin, and not a single interface * in particular, here's our chance to clean it up. */ static void raexec_closepi(PILPlugin *pi) { - if ( post_query_ops != NULL ) { - g_hash_table_destroy(post_query_ops); - } } /* * raexec_close_intf called as part of shutting down the md5 HBauth interface. * If there was any global data allocated, or file descriptors opened, etc. * which is associated with the md5 implementation, here's our chance * to clean it up. */ static PIL_rc raexec_closeintf(PILInterface *pi, void *pd) { return PIL_OK; } PIL_PLUGIN_BOILERPLATE("1.0", Debug, raexec_closepi); 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); - post_query_ops = g_hash_table_new(g_int_hash, g_int_equal); - /* Register our interfaces */ return imports->register_interface(us, PIL_PLUGINTYPE_S, PIL_PLUGIN_S, &raops, raexec_closeintf, &OurInterface, &OurImports, interfprivate); } /* * Real work starts here ;-) */ static int -execra( const char * ra_name, const char * op, GHashTable * cmd_params, - GHashTable * env_params, gboolean need_metadata, int * call_key) +execra( const char * ra_name, const char * op, + GHashTable * cmd_params, GHashTable * env_params ) { + char *ra_name_dup, *base_name; + GString * ra_dirname; + + uniform_ret_execra_t exit_value; + cl_log(LOG_DEBUG, "To execute a RA %s", ra_name); /* Prepare the call parameter */ if (!cmd_params) { - cl_log(LOG_ERR, "OCF RA should have no command-line \ - parameters."); + if (g_hash_table_size(cmd_params) > 0) { + cl_log(LOG_ERR, "OCF RA should have no "\ + "command-line parameters."); + } } + + ra_dirname = g_string_new(ra_name); + ra_name_dup = strndup(ra_name, RA_MAX_DIRNAME_LENGTH); + base_name = basename(ra_name_dup); + /* + * If ra_name only contains basename, then append RA_PATH. + * If ra_name is a pathname, then don't deal with it. + */ + if ( strncmp(ra_name, base_name, RA_MAX_BASENAME_LENGTH) == 0 ) { + g_string_insert(ra_dirname, 0, RA_PATH); + } + free(ra_name_dup); - /* Fork a child and execute the RA */ - *call_key = fork_and_execra(ra_name, op, NULL, - env_params, need_metadata); - - if (*call_key <= 0) { - return -1; - } - else { - return 0; /* return ok */ + /* execute the RA */ + raexec_setenv(env_params); + cl_log(LOG_ERR, "ra_dirname is:%s", ra_dirname->str); + execl(ra_dirname->str, ra_dirname->str, op, NULL); + + switch (errno) { + case ENOENT: /* No such file or directory */ + case EISDIR: /* Is a directory */ + exit_value = EXECRA_NO_RA; + break; + + default: + exit_value = EXECRA_EXEC_UNKNOWN_ERROR; } + + cl_log(LOG_ERR, "execl error when to execute RA %s.", ra_name); + g_string_free(ra_dirname, TRUE); + exit(exit_value); } -static int -post_query_result(int exec_key, int * result, char ** meta_data) +static uniform_ret_execra_t +map_ra_retvalue(int ret_execra, const char * op) { - int ret; - gpointer org_key, org_value; - gboolean found = FALSE; - - if ( post_query_ops == NULL ) { - return -1; - } - - found = g_hash_table_lookup_extended(post_query_ops, - &exec_key, &org_key, &org_value); - if ( !found ) { - cl_log(LOG_ERR,"No this child %d need post query.", exec_key); - return -1; - } - ret = waitpid(exec_key, result, WNOHANG); - if ( ret == 0 ) { - cl_log(LOG_DEBUG, "process %d don't exit yet.", exec_key); - /* return at once to avoid remove item in 'post_query_ops' */ - return 0; - } - - if ( ret == -1 ) { - cl_log(LOG_ERR, "error when fetching %d exit status.", - exec_key); - } - - if ((ret > 0) && (*(int*)org_value > 0) && ( meta_data != NULL )) { - read_pipe(*(int*)org_value, meta_data); - } - - g_free(org_key); - g_free(org_value); - g_hash_table_remove(post_query_ops, &exec_key); - - return ret; + /* Because the UNIFORM_RET_EXECRA is compatible with OCF standard */ + return ret_execra; } -/* Possible bug for pipe using such as exceeding the buffer length ? */ static int -fork_and_execra(const char * ra_name, const char * op, const char * cmd_params, - GHashTable * env_params, gboolean need_metadata) +get_resource_list(GList ** rsc_info) { - int cpid; - int fd[2]; + struct dirent **namelist; + int file_num; - cl_log(LOG_DEBUG, "Will to execute RA %s.", ra_name); - if (need_metadata == TRUE) { - if ( pipe(fd) < 0 ) { - cl_log(LOG_ERR,"pipe create error when to execute %s.", - ra_name); - return -1; - } + if ( rsc_info == NULL ) { + cl_log(LOG_ERR, "Parameter error: get_resource_list"); + return -2; } - if ( (cpid=fork()) < 0 ) { - cl_log(LOG_ERR, "Fork failed when to execute %s.", ra_name); - return -1; - } - - if ( cpid > 0 ) { - /* In parent process */ - /* close write fd */ - if ( need_metadata == TRUE ) { - close(fd[1]); - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(fd[0])); - } - else { - g_hash_table_insert(post_query_ops, - g_intdup(cpid), g_intdup(0)); - } - return cpid; - } else { - /* in child process */ - /* close read fd */ - cl_log(LOG_DEBUG, "In forked child %d.", getpid()); - - if ( need_metadata == TRUE ) { - close(fd[0]); - if ( fd[1] != STDOUT_FILENO ) { - if (dup2(fd[1], STDOUT_FILENO)!=STDOUT_FILENO) { - cl_log(LOG_ERR,"dup2 error when to "\ - "execute RA."); - exit(-1); - } + 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) { + cl_log(LOG_ERR, "scandir failed in OCF RA plugin"); + return -2; + } else + { + while (file_num--) { + rsc_info_t * rsc_info_tmp; + if (*(namelist[file_num]->d_name) != '.') { + rsc_info_tmp = g_new(rsc_info_t, 1); + rsc_info_tmp->rsc_type = + g_strdup(namelist[file_num]->d_name); + /* + * Since the version definition isn't cleat yet, + * the version is setted 1.0. + */ + rsc_info_tmp->version = g_strdup("1.0"); } - close(fd[1]); - } - - raexec_setenv(env_params); - if ( execl(ra_name, ra_name, op, NULL) < 0 ) { - cl_log(LOG_ERR, "execl error when to execute RA %s.", - ra_name); + free(namelist[file_num]); } - exit(-1); - } -} - -static int -read_pipe(int fd, char ** meta_data) -{ - const int BUFFLEN = 81; - char buffer[BUFFLEN]; - int readlen; - GString * gstr_tmp; - - *meta_data = NULL; - gstr_tmp = g_string_new(""); - do { - memset(buffer, 0, BUFFLEN); - readlen = read(fd, buffer, BUFFLEN - 1); - if ( readlen > 0 ) { - g_string_append(gstr_tmp, buffer); - } - } while (readlen == BUFFLEN - 1); - close(fd); - - if (readlen < 0) { - cl_log(LOG_ERR, "read pipe error when execute RA."); - return -1; + free(namelist); } - if ( gstr_tmp->len == 0 ) { - cl_log(LOG_INFO, "read 0 byte from this pipe when execute RA."); - return 0; - } - - *meta_data = malloc(gstr_tmp->len + 1); - if ( *meta_data == NULL ) { - cl_log(LOG_ERR, "malloc error in read_pipe."); - return -1; - } - - (*meta_data)[0] = '\0'; - (*meta_data)[gstr_tmp->len] = '\0'; - strncpy(*meta_data, gstr_tmp->str, gstr_tmp->len); - g_string_free(gstr_tmp, TRUE); - return 0; + return 0; } static int raexec_setenv(GHashTable * env_params) { if (!env_params) { return -1; } g_hash_table_foreach(env_params, set_env, NULL); /* Need to free the env_params ? */ return 0; } -static int * -g_intdup(gint value) -{ - gint * tmp; - tmp = g_new(gint,1); - *tmp = value; - return tmp; -} - static void set_env(gpointer key, gpointer value, gpointer user_data) { setenv((const char *)key, (const char *)value, 1); /*Need to free the memory to which key and value point?*/ }