#include "src/include/pmix_config.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#include "pmix_common.h"
#include "src/class/pmix_list.h"
#include "src/include/pmix_globals.h"
#include "src/mca/base/pmix_base.h"
#include "src/mca/base/pmix_mca_base_component_repository.h"
#include "src/mca/mca.h"
#include "src/mca/pdl/base/base.h"
#include "src/mca/pinstalldirs/pinstalldirs.h"
#include "src/util/pmix_argv.h"
#include "src/util/pmix_output.h"
#include "src/util/pmix_environ.h"
#include "src/util/pmix_show_help.h"
#if PMIX_HAVE_PDL_SUPPORT
static void find_dyn_components(const char *path, pmix_mca_base_framework_t *framework,
const char **names, bool include_mode);
#endif
static int component_find_check(pmix_mca_base_framework_t *framework,
char **requested_component_names);
struct pmix_mca_base_open_only_dummy_component_t {
pmix_mca_base_component_t version;
};
typedef struct pmix_mca_base_open_only_dummy_component_t pmix_mca_base_open_only_dummy_component_t;
static char negate[] = "^";
static bool use_component(const bool include_mode, const char **requested_component_names,
const char *component_name);
int pmix_mca_base_component_find(const char *directory, pmix_mca_base_framework_t *framework,
bool ignore_requested, bool open_dso_components)
{
const pmix_mca_base_component_t **static_components = framework->framework_static_components;
char **requested_component_names = NULL;
pmix_mca_base_component_list_item_t *cli;
bool include_mode = true;
int ret;
PMIX_HIDE_UNUSED_PARAMS(open_dso_components);
pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, framework->framework_output,
"mca: base: component_find: searching %s for %s components",
(NULL == directory) ? "NULL" : directory,
framework->framework_name);
if (!ignore_requested) {
ret = pmix_mca_base_component_parse_requested(framework->framework_selection, &include_mode,
&requested_component_names);
if (PMIX_SUCCESS != ret) {
return ret;
}
}
if (static_components) {
for (int i = 0; NULL != static_components[i]; ++i) {
if (use_component(include_mode, (const char **) requested_component_names,
static_components[i]->pmix_mca_component_name)) {
cli = PMIX_NEW(pmix_mca_base_component_list_item_t);
if (NULL == cli) {
ret = PMIX_ERR_OUT_OF_RESOURCE;
goto component_find_out;
}
cli->cli_component = static_components[i];
pmix_list_append(&framework->framework_components, (pmix_list_item_t *) cli);
}
}
}
#if PMIX_HAVE_PDL_SUPPORT
if (open_dso_components && !pmix_mca_base_component_disable_dlopen) {
find_dyn_components(directory, framework, (const char **) requested_component_names,
include_mode);
} else {
pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_INFO, 0,
"pmix:mca: base: component_find: dso loading for %s MCA components disabled",
framework->framework_name);
}
#endif
if (include_mode) {
ret = component_find_check(framework, requested_component_names);
} else {
ret = PMIX_SUCCESS;
}
component_find_out:
if (NULL != requested_component_names) {
PMIx_Argv_free(requested_component_names);
}
return ret;
}
int pmix_mca_base_component_find_finalize(void)
{
return PMIX_SUCCESS;
}
int pmix_mca_base_components_filter(pmix_mca_base_framework_t *framework)
{
pmix_list_t *components = &framework->framework_components;
int output_id = framework->framework_output;
pmix_mca_base_component_list_item_t *cli, *next;
char **requested_component_names = NULL;
bool include_mode, can_use;
int ret;
assert(NULL != components);
if (NULL == framework->framework_selection) {
return PMIX_SUCCESS;
}
ret = pmix_mca_base_component_parse_requested(framework->framework_selection, &include_mode,
&requested_component_names);
if (PMIX_SUCCESS != ret) {
return ret;
}
PMIX_LIST_FOREACH_SAFE (cli, next, components, pmix_mca_base_component_list_item_t) {
const pmix_mca_base_component_t *component = cli->cli_component;
can_use = use_component(include_mode, (const char **) requested_component_names,
cli->cli_component->pmix_mca_component_name);
if (!can_use) {
pmix_list_remove_item(components, &cli->super);
pmix_mca_base_component_unload(component, output_id);
PMIX_RELEASE(cli);
}
}
if (include_mode) {
ret = component_find_check(framework, requested_component_names);
} else {
ret = PMIX_SUCCESS;
}
if (NULL != requested_component_names) {
PMIx_Argv_free(requested_component_names);
}
return ret;
}
#if PMIX_HAVE_PDL_SUPPORT
static void find_dyn_components(const char *path, pmix_mca_base_framework_t *framework,
const char **names, bool include_mode)
{
pmix_mca_base_component_repository_item_t *ri;
pmix_list_t *dy_components;
int ret;
pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, framework->framework_output,
"mca: base: find_dyn_components: checking %s for %s components",
(NULL == path) ? "NULL" : path,
framework->framework_name);
if (NULL != path) {
ret = pmix_mca_base_component_repository_add(framework->framework_project, path);
if (PMIX_SUCCESS != ret) {
return;
}
}
ret = pmix_mca_base_component_repository_get_components(framework, &dy_components);
if (PMIX_SUCCESS != ret) {
return;
}
PMIX_LIST_FOREACH (ri, dy_components, pmix_mca_base_component_repository_item_t) {
if (use_component(include_mode, names, ri->ri_name)) {
pmix_mca_base_component_repository_open(framework, ri);
}
}
}
#endif
static bool use_component(const bool include_mode, const char **requested_component_names,
const char *component_name)
{
bool found = false;
const char **req_comp_name = requested_component_names;
if (NULL == req_comp_name) {
return true;
}
while (*req_comp_name != NULL) {
if (strcmp(component_name, *req_comp_name) == 0) {
found = true;
break;
}
req_comp_name++;
}
return (include_mode && found) || !(include_mode || found);
}
static int component_find_check(pmix_mca_base_framework_t *framework,
char **requested_component_names)
{
pmix_list_t *components = &framework->framework_components;
pmix_mca_base_component_list_item_t *cli;
if (NULL == requested_component_names) {
return PMIX_SUCCESS;
}
for (int i = 0; NULL != requested_component_names[i]; ++i) {
bool found = false;
PMIX_LIST_FOREACH (cli, components, pmix_mca_base_component_list_item_t) {
if (0
== strcmp(requested_component_names[i],
cli->cli_component->pmix_mca_component_name)) {
found = true;
break;
}
}
if (!found && pmix_mca_base_component_show_load_errors) {
char h[PMIX_MAXHOSTNAMELEN] = {0};
gethostname(h, sizeof(h) - 1);
pmix_show_help("help-pmix-mca-base.txt", "find-available:not-valid", true, h,
framework->framework_name, requested_component_names[i]);
if (pmix_mca_base_component_abort_on_load_error) {
return PMIX_ERR_NOT_FOUND;
}
}
}
return PMIX_SUCCESS;
}
int pmix_mca_base_component_parse_requested(const char *requested, bool *include_mode,
char ***requested_component_names)
{
const char *requested_orig = requested;
*requested_component_names = NULL;
*include_mode = true;
if (NULL == requested || 0 == strlen(requested)) {
return PMIX_SUCCESS;
}
*include_mode = requested[0] != negate[0];
requested += strspn(requested, negate);
if (NULL != strstr(requested, negate)) {
pmix_show_help("help-pmix-mca-base.txt", "framework-param:too-many-negates", true,
requested_orig);
return PMIX_ERROR;
}
*requested_component_names = PMIx_Argv_split(requested, ',');
return PMIX_SUCCESS;
}