root/opal/mca/dl/dlopen/dl_dlopen_module.c

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

DEFINITIONS

This source file includes following definitions.
  1. do_dlopen
  2. dlopen_open
  3. dlopen_lookup
  4. dlopen_close
  5. dlopen_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) 2018      Amazon.com, Inc. or its affiliates.  All Rights reserved.
   8  * $COPYRIGHT$
   9  *
  10  * Additional copyrights may follow
  11  *
  12  * $HEADER$
  13  */
  14 
  15 #include "opal_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 "opal/constants.h"
  25 #include "opal/mca/dl/dl.h"
  26 #include "opal/util/argv.h"
  27 #include "opal/util/printf.h"
  28 
  29 #include "dl_dlopen.h"
  30 
  31 
  32 /*
  33  * Trivial helper function to avoid replicating code
  34  */
  35 static void do_dlopen(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 dlopen_open(const char *fname, bool use_ext, bool private_namespace,
  53                        opal_dl_handle_t **handle, char **err_msg)
  54 {
  55     assert(handle);
  56 
  57     *handle = NULL;
  58 
  59     /* Setup the dlopen flags */
  60     int flags = RTLD_LAZY;
  61     if (private_namespace) {
  62         flags |= RTLD_LOCAL;
  63     } else {
  64         flags |= RTLD_GLOBAL;
  65     }
  66 
  67     /* If the caller wants to use filename extensions, loop through
  68        them */
  69     void *local_handle = NULL;
  70     if (use_ext && NULL != fname) {
  71         int i;
  72         char *ext;
  73 
  74         for (i = 0, ext = mca_dl_dlopen_component.filename_suffixes[i];
  75              NULL != ext;
  76              ext = mca_dl_dlopen_component.filename_suffixes[++i]) {
  77             char *name;
  78 
  79             opal_asprintf(&name, "%s%s", fname, ext);
  80             if (NULL == name) {
  81                 return OPAL_ERR_IN_ERRNO;
  82             }
  83 
  84             /* Does the file exist? */
  85             struct stat buf;
  86             if (stat(name, &buf) < 0) {
  87                 free(name);
  88                 if (NULL != err_msg) {
  89                     *err_msg = "File not found";
  90                 }
  91                 continue;
  92             }
  93 
  94             /* Yes, the file exists -- try to dlopen it.  If we can't
  95                dlopen it, bail. */
  96             do_dlopen(name, flags, &local_handle, err_msg);
  97             free(name);
  98             break;
  99         }
 100     }
 101 
 102     /* Otherwise, the caller does not want to use filename extensions,
 103        so just use the single filename that the caller provided */
 104     else {
 105         do_dlopen(fname, flags, &local_handle, err_msg);
 106     }
 107 
 108     if (NULL != local_handle) {
 109         *handle = calloc(1, sizeof(opal_dl_handle_t));
 110         (*handle)->dlopen_handle = local_handle;
 111 
 112 #if OPAL_ENABLE_DEBUG
 113         if( NULL != fname ) {
 114             (*handle)->filename = strdup(fname);
 115         }
 116         else {
 117             (*handle)->filename = strdup("(null)");
 118         }
 119 #endif
 120     }
 121     return (NULL != local_handle) ? OPAL_SUCCESS : OPAL_ERROR;
 122 }
 123 
 124 
 125 static int dlopen_lookup(opal_dl_handle_t *handle, const char *symbol,
 126                          void **ptr, char **err_msg)
 127 {
 128     assert(handle);
 129     assert(handle->dlopen_handle);
 130     assert(symbol);
 131     assert(ptr);
 132 
 133     *ptr = dlsym(handle->dlopen_handle, symbol);
 134     if (NULL != *ptr) {
 135         return OPAL_SUCCESS;
 136     }
 137 
 138     if (NULL != err_msg) {
 139         *err_msg = dlerror();
 140     }
 141     return OPAL_ERROR;
 142 }
 143 
 144 
 145 static int dlopen_close(opal_dl_handle_t *handle)
 146 {
 147     assert(handle);
 148 
 149     int ret;
 150     ret = dlclose(handle->dlopen_handle);
 151 
 152 #if OPAL_ENABLE_DEBUG
 153     free(handle->filename);
 154 #endif
 155     free(handle);
 156 
 157     return ret;
 158 }
 159 
 160 /*
 161  * Scan all the files in a directory (or path) and invoke a callback
 162  * on each one.
 163  */
 164 static int dlopen_foreachfile(const char *search_path,
 165                               int (*func)(const char *filename, void *data),
 166                               void *data)
 167 {
 168     int ret;
 169     DIR *dp = NULL;
 170     char **dirs = NULL;
 171     char **good_files = NULL;
 172 
 173     dirs = opal_argv_split(search_path, OPAL_ENV_SEP);
 174     for (int i = 0; NULL != dirs && NULL != dirs[i]; ++i) {
 175 
 176         dp = opendir(dirs[i]);
 177         if (NULL == dp) {
 178             ret = OPAL_ERR_IN_ERRNO;
 179             goto error;
 180         }
 181 
 182         struct dirent *de;
 183         while (NULL != (de = readdir(dp))) {
 184 
 185             /* Make the absolute path name */
 186             char *abs_name = NULL;
 187             opal_asprintf(&abs_name, "%s/%s", dirs[i], de->d_name);
 188             if (NULL == abs_name) {
 189                 ret = OPAL_ERR_IN_ERRNO;
 190                 goto error;
 191             }
 192 
 193             /* Stat the file */
 194             struct stat buf;
 195             if (stat(abs_name, &buf) < 0) {
 196                 free(abs_name);
 197                 ret = OPAL_ERR_IN_ERRNO;
 198                 goto error;
 199             }
 200 
 201             /* Skip if not a file */
 202             if (!S_ISREG(buf.st_mode)) {
 203                 free(abs_name);
 204                 continue;
 205             }
 206 
 207             /* Find the suffix */
 208             char *ptr = strrchr(abs_name, '.');
 209             if (NULL != ptr) {
 210 
 211                 /* Skip libtool files */
 212                 if (strcmp(ptr, ".la") == 0 ||
 213                     strcmp(ptr, ".lo") == 0) {
 214                     free (abs_name);
 215                     continue;
 216                 }
 217 
 218                 *ptr = '\0';
 219             }
 220 
 221             /* Have we already found this file?  Or already found a
 222                file with the same basename (but different suffix)? */
 223             bool found = false;
 224             for (int j = 0; NULL != good_files &&
 225                      NULL != good_files[j]; ++j) {
 226                 if (strcmp(good_files[j], abs_name) == 0) {
 227                     found = true;
 228                     break;
 229                 }
 230             }
 231 
 232             if (!found) {
 233                 opal_argv_append_nosize(&good_files, abs_name);
 234             }
 235             free(abs_name);
 236         }
 237         closedir(dp);
 238     }
 239     dp = NULL;
 240 
 241     /* Invoke the callback on all the found files */
 242     if (NULL != good_files) {
 243         for (int i = 0; NULL != good_files[i]; ++i) {
 244             ret = func(good_files[i], data);
 245             if (OPAL_SUCCESS != ret) {
 246                 goto error;
 247             }
 248         }
 249     }
 250 
 251     ret = OPAL_SUCCESS;
 252 
 253  error:
 254     if (NULL != dp) {
 255         closedir(dp);
 256     }
 257     if (NULL != dirs) {
 258         opal_argv_free(dirs);
 259     }
 260     if (NULL != good_files) {
 261         opal_argv_free(good_files);
 262     }
 263 
 264     return ret;
 265 }
 266 
 267 
 268 /*
 269  * Module definition
 270  */
 271 opal_dl_base_module_t opal_dl_dlopen_module = {
 272     .open = dlopen_open,
 273     .lookup = dlopen_lookup,
 274     .close = dlopen_close,
 275     .foreachfile = dlopen_foreachfile
 276 };

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