diff --git a/lib/services/services_linux.c b/lib/services/services_linux.c index 8dbcc6d2590..59f44096699 100644 --- a/lib/services/services_linux.c +++ b/lib/services/services_linux.c @@ -19,10 +19,14 @@ #include #include #include +#include #include #include #include #include +#include +#include + #include "crm/crm.h" #include "crm/common/mainloop.h" @@ -1174,6 +1178,10 @@ services__execute_file(svc_action_t *op) struct stat st; struct sigchld_data_s data; + if (services__execute_file_as_plugin(op) == pcmk_rc_ok){ + return pcmk_rc_ok; + } + // Catch common failure conditions early if (stat(op->opaque->exec, &st) != 0) { rc = errno; @@ -1436,3 +1444,102 @@ services_os_get_directory_list(const char *root, gboolean files, gboolean execut return result; } + +int +services__execute_file_as_plugin(svc_action_t *op) { + void *handle; + int (*exec)(int, int, char *); + char *lib_error; + int exec_status; + char dst[200] = "/usr/lib/ocf/resource.d/heartbeat/"; + strcat(dst, op->agent); + handle = dlopen (dst, RTLD_NOW | RTLD_LOCAL); + + if (!handle) { + // можно что-то залогировать + return pcmk_rc_error; + } else { + // можно что-то залогировать + exec = dlsym(handle, "handler"); + + if ((lib_error = dlerror()) != NULL){ + free(lib_error); + + // можно что-то залогировать + // ситуация, когда мы смогли открыть агента + // как разделяемую библиотеку, но не нашли + // нужного метода (что-то странное) + return pcmk_rc_error; + } else { + char num[10]; + int out_fd; + int err_fd; + char out_file_name[100] = "outfd-"; + char err_file_name[100] = "errfd-"; + + add_action_env_vars(op); + + sprintf(num, "%d", getpid()); + strcat(out_file_name, num); + strcat(err_file_name, num); + + out_fd = memfd_create(out_file_name, MFD_ALLOW_SEALING); + err_fd = memfd_create(err_file_name, MFD_ALLOW_SEALING); + + exec_status = exec(out_fd, err_fd, op->action); + { + int size_out = lseek(out_fd, 0, SEEK_END); // SEEK_CUR ? + int size_err = lseek(err_fd, 0, SEEK_END); + if (size_out > 0) { + char *buf_out = (char *)malloc(sizeof(char) * (size_out + 1)); + lseek(out_fd, 0, SEEK_SET); + if (read(out_fd, buf_out, size_out) >= 0) { + buf_out[size_out] = '\0'; + op->stdout_data = buf_out; + } + } else { + op->stdout_data = NULL; + } + + if (size_err > 0) { + char *buf_err = (char *)malloc(sizeof(char) * (size_err + 1)); + lseek(err_fd, 0, SEEK_SET); + if (read(err_fd, buf_err, size_err) >= 0) { + buf_err[size_err] = '\0'; + op->stderr_data = buf_err; + } + } else { + op->stderr_data = NULL; + } + + if (close(out_fd) < 0) { + crm_info("Error '%s'", "a"); + } + if (close(err_fd) < 0) { + crm_info("Error 's'", "b"); + } + + op->rc = exec_status; + op->status = PCMK_EXEC_DONE; + op->pid = 0; + if (op->interval_ms != 0) { + // Recurring operations must be either cancelled or rescheduled + if (op->cancel) { + services__set_cancelled(op); + cancel_recurring_action(op); + } else { + op->opaque->repeat_timer = g_timeout_add(op->interval_ms, + recurring_action_timer, + (void *) op); + } + } + if (op->opaque->callback) { + op->opaque->callback(op); + } + } + dlclose(handle); + return pcmk_rc_ok; + //dlclose(handle); + } + } +} diff --git a/lib/services/services_private.h b/lib/services/services_private.h index 7285fc33f83..2b95ba09c94 100644 --- a/lib/services/services_private.h +++ b/lib/services/services_private.h @@ -57,6 +57,9 @@ GList *services_os_get_directory_list(const char *root, gboolean files, gboolean G_GNUC_INTERNAL int services__execute_file(svc_action_t *op); +G_GNUC_INTERNAL +int services__execute_file_as_plugin(svc_action_t *op); + G_GNUC_INTERNAL gboolean cancel_recurring_action(svc_action_t * op);