/*
 * Open up all directories in a given path and search for components of
 * the specified type (and possibly of a given name).
 *
 * Note that we use our own path iteration functionality because we
 * need to look at companion .ompi_info files in the same directory as
 * the library to generate dependencies, etc.
 */
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",
                         path, framework->framework_name);

    if (NULL != path) {
        ret = pmix_mca_base_component_repository_add(path);
        if (PMIX_SUCCESS != ret) {
            return;
        }
    }

    ret = pmix_mca_base_component_repository_get_components(framework, &dy_components);
    if (PMIX_SUCCESS != ret) {
        return;
    }

    /* Iterate through the repository and find components that can be included */
    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);
        }
    }
}
/*
 * Open up all directories in a given path and search for components of
 * the specified type (and possibly of a given name).
 *
 * Note that we use our own path iteration functionality (vs. ltdl's
 * lt_dladdsearchdir() functionality) because we need to look at
 * companion .ompi_info files in the same directory as the library to
 * generate dependencies, etc.  If we use the plain lt_dlopen()
 * functionality, we would not get the directory name of the file
 * finally opened in recursive dependency traversals.
 */
static void find_dyn_components(const char *path, const char *type_name, 
                                const char **names, bool include_mode,
                                opal_list_t *found_components)
{
    int i, len;
    char *path_to_use = NULL, *dir, *end;
    component_file_item_t *file;
    opal_list_item_t *cur;
    char prefix[32 + MCA_BASE_MAX_TYPE_NAME_LEN], *basename;
    
    /* If path is NULL, iterate over the set of directories specified by
       the MCA param mca_base_component_path.  If path is not NULL, then
       use that as the path. */
  
    if (NULL == path) {
        if (NULL != mca_base_component_path) {
            path_to_use = strdup (mca_base_component_path);
        } else {
            /* If there's no path, then there's nothing to search -- we're
               done */
            return;
        }

        if (NULL == path_to_use) {
            /* out of memory */
            return;
        }
    } else {
        path_to_use = strdup(path);
    }
  
    /* If we haven't done so already, iterate over all the files in
       the directories in the path and make a master array of all the
       matching filenames that we find.  Save the filenames in an
       argv-style array.  Re-scan do this if the mca_component_path
       has changed. */
    if (NULL == found_filenames || 
        (NULL != last_path_to_use && 
         0 != strcmp(path_to_use, last_path_to_use))) {
        if (NULL != found_filenames) {
            opal_argv_free(found_filenames);
            found_filenames = NULL;
            free(last_path_to_use);
            last_path_to_use = NULL;
        }
        if (NULL == last_path_to_use) {
            last_path_to_use = strdup(path_to_use);
        }

        dir = path_to_use;
        if (NULL != dir) {
            do {
                end = strchr(dir, OPAL_ENV_SEP);
                if (NULL != end) {
                    *end = '\0';
                }
                if ((0 == strcmp(dir, "USER_DEFAULT") ||
                     0 == strcmp(dir, "USR_DEFAULT"))
                    && NULL != mca_base_user_default_path) {
                    if (0 != lt_dlforeachfile(mca_base_user_default_path,
                                              save_filename, NULL)) {
                        break;
                    }
                } else if (0 == strcmp(dir, "SYS_DEFAULT") ||
                           0 == strcmp(dir, "SYSTEM_DEFAULT")) {
                    if (0 != lt_dlforeachfile(mca_base_system_default_path,
                                              save_filename, NULL)) {
                        break;
                    }                    
                } else {
                    if (0 != lt_dlforeachfile(dir, save_filename, NULL)) {
                        break;
                    }
                }
                dir = end + 1;
            } while (NULL != end);
        }
    }
    
    /* Look through the list of found files and find those that match
       the desired framework name */
    snprintf(prefix, sizeof(prefix) - 1, component_template, type_name);
    len = strlen(prefix);
    OBJ_CONSTRUCT(&found_files, opal_list_t);
    for (i = 0; NULL != found_filenames && NULL != found_filenames[i]; ++i) {
        basename = strrchr(found_filenames[i], '/');
        if (NULL == basename) {
            basename = found_filenames[i];
        } else {
            basename += 1;
        }
        
        if (0 != strncmp(basename, prefix, len)) {
            continue;
        }
        
        /* We found a match; save all the relevant details in the
           found_files list */
        file = OBJ_NEW(component_file_item_t);
        if (NULL == file) {
            return;
        }
        strncpy(file->type, type_name, MCA_BASE_MAX_TYPE_NAME_LEN);
        file->type[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0';
        strncpy(file->name, basename + len, MCA_BASE_MAX_COMPONENT_NAME_LEN);
        file->name[MCA_BASE_MAX_COMPONENT_NAME_LEN] = '\0';
        strncpy(file->basename, basename, OPAL_PATH_MAX);
        file->basename[OPAL_PATH_MAX] = '\0';
        strncpy(file->filename, found_filenames[i], OPAL_PATH_MAX);
        file->filename[OPAL_PATH_MAX] = '\0';
        file->status = UNVISITED;

        opal_list_append(&found_files, (opal_list_item_t *) 
                         file);
    }

    /* Iterate through all the filenames that we found that matched
       the framework we were looking for.  Since one component may
       [try to] call another to be loaded, only try to load the
       UNVISITED files.  Also, ignore the return code -- basically,
       give every file one chance to try to load.  If they load,
       great.  If not, great. */
    for (cur = opal_list_get_first(&found_files); 
         opal_list_get_end(&found_files) != cur;
         cur = opal_list_get_next(cur)) {
        file = (component_file_item_t *) cur;

        if( UNVISITED == file->status ) {
            bool op = true;
            file->status = CHECKING_CYCLE;

            op = use_component(include_mode, names, file->name);
            if( true == op ) {
                open_component(file, found_components);
            }
        }
    }
    
    /* So now we have a final list of loaded components.  We can free all
       the file information. */
    for (cur = opal_list_remove_first(&found_files); 
         NULL != cur;
         cur = opal_list_remove_first(&found_files)) {
        OBJ_RELEASE(cur);
    }
    OBJ_DESTRUCT(&found_files);

    /* All done, now let's cleanup */
    free(path_to_use);
}
int mca_base_components_filter (const char *framework_name, opal_list_t *components, int output_id,
                                const char *filter_names, uint32_t filter_flags)
{
    mca_base_component_list_item_t *cli, *next;
    char **requested_component_names = NULL;
    bool include_mode, can_use;
    int ret;

    assert (NULL != components);

    if (0 == filter_flags && NULL == filter_names) {
        return OPAL_SUCCESS;
    }

    ret = mca_base_component_parse_requested (filter_names, &include_mode,
                           &requested_component_names);
    if (OPAL_SUCCESS != ret) {
        return ret;
    }

    OPAL_LIST_FOREACH_SAFE(cli, next, components, mca_base_component_list_item_t) {
        const mca_base_component_t *component = cli->cli_component;
        mca_base_open_only_dummy_component_t *dummy =
            (mca_base_open_only_dummy_component_t *) cli->cli_component;

        can_use = use_component (include_mode, (const char **) requested_component_names,
                                 cli->cli_component->mca_component_name);

        if (!can_use || (filter_flags & dummy->data.param_field) != filter_flags) {
            if (can_use && (filter_flags & MCA_BASE_METADATA_PARAM_CHECKPOINT) &&
                !(MCA_BASE_METADATA_PARAM_CHECKPOINT & dummy->data.param_field)) {
                opal_output_verbose(10, output_id,
                                    "mca: base: components_filter: "
                                    "(%s) Component %s is *NOT* Checkpointable - Disabled",
                                    component->reserved,
                                    component->mca_component_name);
            }

            opal_list_remove_item (components, &cli->super);

            mca_base_component_unload (component, output_id);

            OBJ_RELEASE(cli);
        } else if (filter_flags & MCA_BASE_METADATA_PARAM_CHECKPOINT) {
            opal_output_verbose(10, output_id,
                                "mca: base: components_filter: "
                                "(%s) Component %s is Checkpointable",
                                component->reserved,
                                component->mca_component_name);
        }
    }

    if (include_mode) {
        ret = component_find_check (framework_name, requested_component_names, components);
    } else {
        ret = OPAL_SUCCESS;
    }

    if (NULL != requested_component_names) {
        opal_argv_free (requested_component_names);
    }

    return ret;
}
/*
 * Function to find as many components of a given type as possible.  This
 * includes statically-linked in components as well as opening up a
 * directory and looking for shared-library MCA components of the
 * appropriate type (load them if available).
 *
 * Return one consolidated array of (mca_base_component_t*) pointing to all
 * available components.
 */
int mca_base_component_find(const char *directory, const char *type, 
                            const mca_base_component_t *static_components[], 
                            const char *requested_components,
                            opal_list_t *found_components,
                            bool open_dso_components)
{
    char **requested_component_names = NULL;
    mca_base_component_list_item_t *cli;
    bool include_mode;
    int i, ret;

    ret = mca_base_component_parse_requested (requested_components, &include_mode,
                           &requested_component_names);
    if (OPAL_SUCCESS != ret) {
        return ret;
    }

    /* Find all the components that were statically linked in */
    OBJ_CONSTRUCT(found_components, opal_list_t);
    for (i = 0; NULL != static_components &&
             NULL != static_components[i]; ++i) {
        if ( use_component(include_mode,
                           (const char**)requested_component_names,
                           static_components[i]->mca_component_name) ) {
            cli = OBJ_NEW(mca_base_component_list_item_t);
            if (NULL == cli) {
                ret = OPAL_ERR_OUT_OF_RESOURCE;
                goto component_find_out;
            }
            cli->cli_component = static_components[i];
            opal_list_append(found_components, (opal_list_item_t *) cli);
        }
    }

#if OPAL_WANT_LIBLTDL
    /* Find any available dynamic components in the specified directory */
    if (open_dso_components && !mca_base_component_disable_dlopen) {
        find_dyn_components(directory, type,
                            (const char**)requested_component_names,
                            include_mode, found_components); 
    } else {
        opal_output_verbose(40, 0, 
                            "mca: base: component_find: dso loading for %s MCA components disabled", 
                            type);
    }
#endif

    if (include_mode) {
        ret = component_find_check (type, requested_component_names, found_components);
    } else {
        ret = OPAL_SUCCESS;
    }


    ret = OPAL_SUCCESS;

component_find_out:

    if (NULL != requested_component_names) {
        opal_argv_free(requested_component_names);
    }

    /* All done */

    return ret;
}
/*
 * Function to find as many components of a given type as possible.  This
 * includes statically-linked in components as well as opening up a
 * directory and looking for shared-library MCA components of the
 * appropriate type (load them if available).
 *
 * Return one consolidated array of (pmix_mca_base_component_t*) pointing to all
 * available components.
 */
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_output_verbose (PMIX_MCA_BASE_VERBOSE_COMPONENT, framework->framework_output,
                         "mca: base: component_find: searching %s for %s components",
                         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;
        }
    }

    /* Find all the components that were statically linked in */
    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
    /* Find any available dynamic components in the specified directory */
    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);
    }

    /* All done */

    return ret;
}
int pmix_mca_base_components_filter (pmix_mca_base_framework_t *framework, uint32_t filter_flags)
{
    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 (0 == filter_flags && 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;
        pmix_mca_base_open_only_dummy_component_t *dummy =
            (pmix_mca_base_open_only_dummy_component_t *) cli->cli_component;

        can_use = use_component(include_mode, (const char **) requested_component_names,
                                cli->cli_component->pmix_mca_component_name);

        if (!can_use || (filter_flags & dummy->data.param_field) != filter_flags) {
            if (can_use && (filter_flags & PMIX_MCA_BASE_METADATA_PARAM_CHECKPOINT) &&
                !(PMIX_MCA_BASE_METADATA_PARAM_CHECKPOINT & dummy->data.param_field)) {
                pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id,
                                    "pmix:mca: base: components_filter: "
                                    "(%s) Component %s is *NOT* Checkpointable - Disabled",
                                    component->reserved,
                                    component->pmix_mca_component_name);
            }

            pmix_list_remove_item(components, &cli->super);

            pmix_mca_base_component_unload(component, output_id);

            PMIX_RELEASE(cli);
        } else if (filter_flags & PMIX_MCA_BASE_METADATA_PARAM_CHECKPOINT) {
            pmix_output_verbose(PMIX_MCA_BASE_VERBOSE_COMPONENT, output_id,
                                "pmix:mca: base: components_filter: "
                                "(%s) Component %s is Checkpointable",
                                component->reserved,
                                component->pmix_mca_component_name);
        }
    }

    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;
}
/*
 * Open up all directories in a given path and search for components of
 * the specified type (and possibly of a given name).
 *
 * Note that we use our own path iteration functionality (vs. ltdl's
 * lt_dladdsearchdir() functionality) because we need to look at
 * companion .ompi_info files in the same directory as the library to
 * generate dependencies, etc.  If we use the plain lt_dlopen()
 * functionality, we would not get the directory name of the file
 * finally opened in recursive dependency traversals.
 */
static void find_dyn_components(const char *path, const char *type_name, 
                                const char **name, bool include_mode,
                                opal_list_t *found_components)
{
    ltfn_data_holder_t params;
    char *path_to_use, *dir, *end;
    component_file_item_t *file;
    opal_list_item_t *cur;

    strncpy(params.type, type_name, MCA_BASE_MAX_TYPE_NAME_LEN);
    params.type[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0';

    params.name[0] = '\0';
  
    /* If path is NULL, iterate over the set of directories specified by
       the MCA param mca_base_component_path.  If path is not NULL, then
       use that as the path. */
  
    if (NULL == path) {
        mca_base_param_lookup_string(mca_base_param_component_path, &path_to_use);
        if (NULL == path_to_use) {
            /* If there's no path, then there's nothing to search -- we're
               done */
            return;
        }
    } else {
        path_to_use = strdup(path);
    }
  
    /* Iterate over all the files in the directories in the path and
       make a master array of all the matching filenames that we
       find. */
  
    OBJ_CONSTRUCT(&found_files, opal_list_t);
    dir = path_to_use;
    if (NULL != dir) {
        do {
            end = strchr(dir, OPAL_ENV_SEP);
            if (NULL != end) {
                *end = '\0';
            }
            if (0 != lt_dlforeachfile(dir, save_filename, &params)) {
                break;
            }
            dir = end + 1;
        } while (NULL != end);
    }
  
    /* Iterate through all the filenames that we found.  Since one
       component may [try to] call another to be loaded, only try to load
       the UNVISITED files.  Also, ignore the return code -- basically,
       give every file one chance to try to load.  If they load, great.
       If not, great. */

    for (cur = opal_list_get_first(&found_files); 
         opal_list_get_end(&found_files) != cur;
         cur = opal_list_get_next(cur)) {
        file = (component_file_item_t *) cur;

        if( UNVISITED == file->status ) {
            bool op = true;
            file->status = CHECKING_CYCLE;

            op = use_component(include_mode, name, file->name);
            if( true == op ) {
                open_component(file, found_components);
            }
        }
    }
    

    /* So now we have a final list of loaded components.  We can free all
       the file information. */
  
    for (cur = opal_list_remove_first(&found_files); 
         NULL != cur;
         cur = opal_list_remove_first(&found_files)) {
        OBJ_RELEASE(cur);
    }

    /* All done, now let's cleanup */
    free(path_to_use);

    OBJ_DESTRUCT(&found_files);
}
/*
 * Function to find as many components of a given type as possible.  This
 * includes statically-linked in components as well as opening up a
 * directory and looking for shared-library MCA components of the
 * appropriate type (load them if available).
 *
 * Return one consolidated array of (mca_base_component_t*) pointing to all
 * available components.
 */
int mca_base_component_find(const char *directory, const char *type, 
                            const mca_base_component_t *static_components[], 
                            char **requested_component_names,
                            bool include_mode,
                            opal_list_t *found_components,
                            bool open_dso_components)
{
    int i;
    opal_list_item_t *item;
    mca_base_component_list_item_t *cli;

    /* Find all the components that were statically linked in */
    OBJ_CONSTRUCT(found_components, opal_list_t);
    for (i = 0; NULL != static_components[i]; ++i) {
        if ( use_component(include_mode,
                           (const char**)requested_component_names,
                           static_components[i]->mca_component_name) ) {
            cli = OBJ_NEW(mca_base_component_list_item_t);
            if (NULL == cli) {
                return OPAL_ERR_OUT_OF_RESOURCE;
            }
            cli->cli_component = static_components[i];
            opal_list_append(found_components, (opal_list_item_t *) cli);
        }
    }

#if OMPI_WANT_LIBLTDL
    /* Find any available dynamic components in the specified directory */
    if (open_dso_components) {
        int param, param_disable_dlopen;
        param = mca_base_param_find("mca", NULL, "component_disable_dlopen");
        mca_base_param_lookup_int(param, &param_disable_dlopen);

        if (0 == param_disable_dlopen) {
            find_dyn_components(directory, type,
                                (const char**)requested_component_names,
                                include_mode, found_components); 
        }
    } else {
        opal_output_verbose(40, 0, 
                            "mca: base: component_find: dso loading for %s MCA components disabled", 
                            type);
    }
#endif

    /* Ensure that *all* requested components exist.  Print a warning
       and abort if they do not. */
    for (i = 0; include_mode && NULL != requested_component_names && 
             NULL != requested_component_names[i]; ++i) {
        for (item = opal_list_get_first(found_components);
             opal_list_get_end(found_components) != item; 
             item = opal_list_get_next(item)) {
            cli = (mca_base_component_list_item_t*) item;
            if (0 == strcmp(requested_component_names[i], 
                            cli->cli_component->mca_component_name)) {
                break;
            }
        }

        if (opal_list_get_end(found_components) == item) {
            char h[MAXHOSTNAMELEN];
            gethostname(h, sizeof(h));
            opal_show_help("help-mca-base.txt", 
                           "find-available:not-valid", true,
                           h, type, requested_component_names[i]);
            return OPAL_ERR_NOT_FOUND;
        }
    }

    /* All done */

    return OPAL_SUCCESS;
}