diff --git a/lib/plugins/lrm/Makefile.am b/lib/plugins/lrm/Makefile.am index 963c79e257..60cdf82d74 100644 --- a/lib/plugins/lrm/Makefile.am +++ b/lib/plugins/lrm/Makefile.am @@ -1,43 +1,43 @@ # # Author: Sun Jiang Dong # Copyright (c) 2004 International Business Machines # # 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 # of the License, or (at your option) any later version. # # This program 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 program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # MAINTAINERCLEANFILES = Makefile.in -INCLUDES = -I$(top_builddir)/include \ - -I$(top_builddir)/libltdl +INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include \ + -I$(top_builddir)/libltdl -I$(top_srcdir)/libltdl halibdir = $(libdir)/@HB_PKG@ havarlibdir = $(localstatedir)/lib/@HB_PKG@ COMMONLIBS = $(top_builddir)/lib/clplumbing/libplumb.la \ $(GLIBLIB) lrmdir = $(HA_VARLIBDIR)/$(HB_PKG)/@LRM_DIR@ plugindir = $(halibdir)/plugins/RAExec plugin_LTLIBRARIES = lsb.la ocf.la heartbeat.la lsb_la_SOURCES = raexeclsb.c lsb_la_LDFLAGS = -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version ocf_la_SOURCES = raexecocf.c ocf_la_LDFLAGS = -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version heartbeat_la_SOURCES = raexechb.c heartbeat_la_LDFLAGS = -L$(top_builddir)/lib/pils -lpils -export-dynamic -module -avoid-version install-exec-local: $(mkinstalldirs) $(DESTDIR)$(lrmdir) -chgrp $(apigid) $(DESTDIR)/$(lrmdir) chmod 770 $(DESTDIR)/$(lrmdir) diff --git a/lib/plugins/lrm/raexechb.c b/lib/plugins/lrm/raexechb.c index 1318a316ba..2695c42b83 100644 --- a/lib/plugins/lrm/raexechb.c +++ b/lib/plugins/lrm/raexechb.c @@ -1,397 +1,399 @@ /* * 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 #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 /* 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); static int post_query_result(int exec_key, int * result, char ** meta_data); /* 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 }; /* * 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) { RA_ARGV params_argv; 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; } 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; } 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; + 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; } - int tmp_len; 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 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 */ - int param_index; 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 ebeca779a4..91aa73a4b4 100644 --- a/lib/plugins/lrm/raexeclsb.c +++ b/lib/plugins/lrm/raexeclsb.c @@ -1,400 +1,399 @@ /* * 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 #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 /* 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); static int post_query_result(int exec_key, int * result, char ** meta_data); /* 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 }; /* * 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) { RA_ARGV params_argv; 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; } /* 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; } 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; } 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; + 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; } - int tmp_len; 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) { - if (user_data == NULL) { - return; - } + int param_index; RA_ARGV * ra_argv = user_data; + if (*ra_argv == NULL ) { return; } /* the parameter index start from 1 */ /* and start from 2 in argv array */ - int param_index; 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; }