root/opal/mca/pmix/pmix4x/pmix/src/mca/pdl/pdlopen/pdl_pdlopen_module.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. do_pdlopen
  2. pdlopen_open
  3. pdlopen_lookup
  4. pdlopen_close
  5. pdlopen_foreachfile

   1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
   2 /*
   3  * Copyright (c) 2015 Cisco Systems, Inc.  All rights reserved.
   4  * Copyright (c) 2015      Los Alamos National Security, LLC. All rights
   5  *                         reserved.
   6  * Copyright (c) 2016      IBM Corporation.  All rights reserved.
   7  * Copyright (c) 2016-2017 Intel, Inc. All rights reserved.
   8  * $COPYRIGHT$
   9  *
  10  * Additional copyrights may follow
  11  *
  12  * $HEADER$
  13  */
  14 
  15 #include <src/include/pmix_config.h>
  16 
  17 #include <stdlib.h>
  18 #include <dlfcn.h>
  19 #include <sys/types.h>
  20 #include <dirent.h>
  21 #include <sys/stat.h>
  22 #include <unistd.h>
  23 
  24 #include "pmix_common.h"
  25 #include "src/mca/pdl/pdl.h"
  26 #include "src/util/argv.h"
  27 #include "src/util/error.h"
  28 
  29 #include "pdl_pdlopen.h"
  30 
  31 
  32 /*
  33  * Trivial helper function to avoid replicating code
  34  */
  35 static void do_pdlopen(const char *fname, int flags,
  36                       void **handle, char **err_msg)
  37 {
  38     assert(handle);
  39 
  40     *handle = dlopen(fname, flags);
  41 
  42     if (NULL != err_msg) {
  43         if (NULL != *handle) {
  44             *err_msg = NULL;
  45         } else {
  46             *err_msg = dlerror();
  47         }
  48     }
  49 }
  50 
  51 
  52 static int pdlopen_open(const char *fname, bool use_ext, bool private_namespace,
  53                        pmix_pdl_handle_t **handle, char **err_msg)
  54 {
  55     int rc;
  56 
  57     assert(handle);
  58 
  59     *handle = NULL;
  60 
  61     /* Setup the dlopen flags */
  62     int flags = RTLD_LAZY;
  63     if (private_namespace) {
  64         flags |= RTLD_LOCAL;
  65     } else {
  66         flags |= RTLD_GLOBAL;
  67     }
  68 
  69     /* If the caller wants to use filename extensions, loop through
  70        them */
  71     void *local_handle = NULL;
  72     if (use_ext && NULL != fname) {
  73         int i;
  74         char *ext;
  75 
  76         for (i = 0, ext = mca_pdl_pdlopen_component.filename_suffixes[i];
  77              NULL != ext;
  78              ext = mca_pdl_pdlopen_component.filename_suffixes[++i]) {
  79             char *name;
  80 
  81             rc = asprintf(&name, "%s%s", fname, ext);
  82             if (0 > rc) {
  83                 return PMIX_ERR_NOMEM;
  84             }
  85             if (NULL == name) {
  86                 return PMIX_ERR_IN_ERRNO;
  87             }
  88 
  89             /* Does the file exist? */
  90             struct stat buf;
  91             if (stat(name, &buf) < 0) {
  92                 free(name);
  93                 if (NULL != err_msg) {
  94                     *err_msg = "File not found";
  95                 }
  96                 continue;
  97             }
  98 
  99             /* Yes, the file exists -- try to dlopen it.  If we can't
 100                dlopen it, bail. */
 101             do_pdlopen(name, flags, &local_handle, err_msg);
 102             free(name);
 103             break;
 104         }
 105     }
 106 
 107     /* Otherwise, the caller does not want to use filename extensions,
 108        so just use the single filename that the caller provided */
 109     else {
 110         do_pdlopen(fname, flags, &local_handle, err_msg);
 111     }
 112 
 113     if (NULL != local_handle) {
 114         *handle = calloc(1, sizeof(pmix_pdl_handle_t));
 115         (*handle)->dlopen_handle = local_handle;
 116 
 117 #if PMIX_ENABLE_DEBUG
 118         if( NULL != fname ) {
 119             (*handle)->filename = strdup(fname);
 120         }
 121         else {
 122             (*handle)->filename = strdup("(null)");
 123         }
 124 #endif
 125     }
 126     return (NULL != local_handle) ? PMIX_SUCCESS : PMIX_ERROR;
 127 }
 128 
 129 
 130 static int pdlopen_lookup(pmix_pdl_handle_t *handle, const char *symbol,
 131                          void **ptr, char **err_msg)
 132 {
 133     assert(handle);
 134     assert(handle->dlopen_handle);
 135     assert(symbol);
 136     assert(ptr);
 137 
 138     *ptr = dlsym(handle->dlopen_handle, symbol);
 139     if (NULL != *ptr) {
 140         return PMIX_SUCCESS;
 141     }
 142 
 143     if (NULL != err_msg) {
 144         *err_msg = dlerror();
 145     }
 146     return PMIX_ERROR;
 147 }
 148 
 149 
 150 static int pdlopen_close(pmix_pdl_handle_t *handle)
 151 {
 152     assert(handle);
 153 
 154     int ret;
 155     ret = dlclose(handle->dlopen_handle);
 156 
 157 #if PMIX_ENABLE_DEBUG
 158     free(handle->filename);
 159 #endif
 160     free(handle);
 161 
 162     return ret;
 163 }
 164 
 165 /*
 166  * Scan all the files in a directory (or path) and invoke a callback
 167  * on each one.
 168  */
 169 static int pdlopen_foreachfile(const char *search_path,
 170                               int (*func)(const char *filename, void *data),
 171                               void *data)
 172 {
 173     int ret;
 174     DIR *dp = NULL;
 175     char **dirs = NULL;
 176     char **good_files = NULL;
 177 
 178     dirs = pmix_argv_split(search_path, PMIX_ENV_SEP);
 179     for (int i = 0; NULL != dirs && NULL != dirs[i]; ++i) {
 180 
 181         dp = opendir(dirs[i]);
 182         if (NULL == dp) {
 183             ret = PMIX_ERR_IN_ERRNO;
 184             goto error;
 185         }
 186 
 187         struct dirent *de;
 188         while (NULL != (de = readdir(dp))) {
 189 
 190             /* Make the absolute path name */
 191             char *abs_name = NULL;
 192             ret = asprintf(&abs_name, "%s/%s", dirs[i], de->d_name);
 193             if (0 > ret) {
 194                 goto error;
 195             }
 196             if (NULL == abs_name) {
 197                 ret = PMIX_ERR_IN_ERRNO;
 198                 goto error;
 199             }
 200 
 201             /* Stat the file */
 202             struct stat buf;
 203             if (stat(abs_name, &buf) < 0) {
 204                 free(abs_name);
 205                 ret = PMIX_ERR_IN_ERRNO;
 206                 goto error;
 207             }
 208 
 209             /* Skip if not a file */
 210             if (!S_ISREG(buf.st_mode)) {
 211                 free(abs_name);
 212                 continue;
 213             }
 214 
 215             /* Find the suffix */
 216             char *ptr = strrchr(abs_name, '.');
 217             if (NULL != ptr) {
 218 
 219                 /* Skip libtool files */
 220                 if (strcmp(ptr, ".la") == 0 ||
 221                     strcmp(ptr, ".lo") == 0) {
 222                     free (abs_name);
 223                     continue;
 224                 }
 225 
 226                 *ptr = '\0';
 227             }
 228 
 229             /* Have we already found this file?  Or already found a
 230                file with the same basename (but different suffix)? */
 231             bool found = false;
 232             for (int j = 0; NULL != good_files &&
 233                      NULL != good_files[j]; ++j) {
 234                 if (strcmp(good_files[j], abs_name) == 0) {
 235                     found = true;
 236                     break;
 237                 }
 238             }
 239 
 240             if (!found) {
 241                 pmix_argv_append_nosize(&good_files, abs_name);
 242             }
 243             free(abs_name);
 244         }
 245         closedir(dp);
 246     }
 247     dp = NULL;
 248 
 249     /* Invoke the callback on all the found files */
 250     if (NULL != good_files) {
 251         for (int i = 0; NULL != good_files[i]; ++i) {
 252             ret = func(good_files[i], data);
 253             if (PMIX_SUCCESS != ret) {
 254                 goto error;
 255             }
 256         }
 257     }
 258 
 259     ret = PMIX_SUCCESS;
 260 
 261  error:
 262     if (NULL != dp) {
 263         closedir(dp);
 264     }
 265     if (NULL != dirs) {
 266         pmix_argv_free(dirs);
 267     }
 268     if (NULL != good_files) {
 269         pmix_argv_free(good_files);
 270     }
 271 
 272     return ret;
 273 }
 274 
 275 
 276 /*
 277  * Module definition
 278  */
 279 pmix_pdl_base_module_t pmix_pdl_pdlopen_module = {
 280     .open = pdlopen_open,
 281     .lookup = pdlopen_lookup,
 282     .close = pdlopen_close,
 283     .foreachfile = pdlopen_foreachfile
 284 };

/* [<][>][^][v][top][bottom][index][help] */