load_module_shlib.c 9.89 KB
Newer Older
1 2 3 4 5
/*
 * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The OpenAirInterface Software Alliance licenses this file to You under
6
 * the OAI Public License, Version 1.1  (the "License"); you may not use this file
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.openairinterface.org/?page_id=698
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *-------------------------------------------------------------------------------
 * For more information about the OpenAirInterface (OAI) Software Alliance:
 *      contact@openairinterface.org
 */
oai's avatar
oai committed
21

22 23 24 25 26 27 28 29 30 31
/*! \file common/utils/load_module_shlib.c
 * \brief shared library loader implementation
 * \author Francois TABURET
 * \date 2017
 * \version 0.1
 * \company NOKIA BellLabs France
 * \email: francois.taburet@nokia-bell-labs.com
 * \note
 * \warning
 */
oai's avatar
oai committed
32 33 34 35 36
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
37
#include <errno.h>
oai's avatar
oai committed
38 39
#include <sys/ioctl.h>
#include <dlfcn.h>
40
#include "openair1/PHY/defs_common.h"
oai's avatar
oai committed
41
#define LOAD_MODULE_SHLIB_MAIN
42 43

#include "common/config/config_userapi.h"
oai's avatar
oai committed
44
#include "load_module_shlib.h"
45 46 47
void loader_init(void) {
  paramdef_t LoaderParams[] = LOADER_PARAMS_DESC;

48
  loader_data.mainexec_buildversion =  PACKAGE_VERSION;
49 50
  int ret = config_get( LoaderParams,sizeof(LoaderParams)/sizeof(paramdef_t),LOADER_CONFIG_PREFIX);
  if (ret <0) {
51
       printf("[LOADER]  configuration couldn't be performed via config module, parameters set to default values\n");
52 53 54
       if (loader_data.shlibpath == NULL) {
         loader_data.shlibpath=DEFAULT_PATH;
        }
55
       loader_data.maxshlibs = DEFAULT_MAXSHLIBS;
56 57 58 59 60 61 62 63 64 65
  }
  loader_data.shlibs = malloc(loader_data.maxshlibs * sizeof(loader_shlibdesc_t));
  if(loader_data.shlibs == NULL) {
     fprintf(stderr,"[LOADER]  %s %d memory allocation error %s\n",__FILE__, __LINE__,strerror(errno));
     exit_fun("[LOADER] unrecoverable error");
  }
  memset(loader_data.shlibs,0,loader_data.maxshlibs * sizeof(loader_shlibdesc_t));
}

/* build the full shared lib name from the module name */
laurent's avatar
laurent committed
66
static char *loader_format_shlibpath(char *modname, char *version)
67
{
laurent's avatar
laurent committed
68 69 70 71 72
  char *tmpstr;
  char *shlibpath = NULL;
  char *shlibversion = NULL;
  // clang-format off
  paramdef_t LoaderParams[] = {
73 74
    {"shlibpath",    NULL, 0, .strptr = &shlibpath,    .defstrval = NULL, TYPE_STRING, 0, NULL},
    {"shlibversion", NULL, 0, .strptr = &shlibversion, .defstrval = "",   TYPE_STRING, 0, NULL}
laurent's avatar
laurent committed
75 76
  };
  // clang-format on
77

laurent's avatar
laurent committed
78
  int ret;
79

laurent's avatar
laurent committed
80 81 82
  /* looks for specific path for this module in the config file */
  /* specific value for a module path and version is located in a modname subsection of the loader section */
  /* shared lib name is formatted as lib<module name><module version>.so */
83 84
  char cfgprefix[sizeof(LOADER_CONFIG_PREFIX)+strlen(modname)+16];
  sprintf(cfgprefix,LOADER_CONFIG_PREFIX ".%s",modname);
laurent's avatar
laurent committed
85
  ret = config_get(LoaderParams, sizeofArray(LoaderParams), cfgprefix);
86
  if (ret <0) {
laurent's avatar
laurent committed
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
    fprintf(stderr, "[LOADER]  %s %d couldn't retrieve config from section %s\n", __FILE__, __LINE__, cfgprefix);
  }
  /* no specific path, use loader default shared lib path */
  if (shlibpath == NULL) {
    shlibpath = loader_data.shlibpath;
  }
  /* no specific shared lib version */
  if (version != NULL) { // version specified as a function parameter
    shlibversion = version;
  }
  if (shlibversion == NULL) { // no specific version specified, neither as a config param or as a function param
    shlibversion = "";
  }
  /* alloc memory for full module shared lib file name */
  tmpstr = malloc(strlen(shlibpath) + strlen(modname) + strlen(shlibversion) + 16);
  if (tmpstr == NULL) {
    fprintf(stderr, "[LOADER] %s %d malloc error loading module %s, %s\n", __FILE__, __LINE__, modname, strerror(errno));
    exit_fun("[LOADER] unrecoverable error");
  }
  if (shlibpath[0] != 0) {
    ret = sprintf(tmpstr, "%s/", shlibpath);
  } else {
    ret = 0;
  }

  sprintf(tmpstr + ret, "lib%s%s.so", modname, shlibversion);
113

laurent's avatar
laurent committed
114
  return tmpstr;
115 116
}

117
int load_module_version_shlib(char *modname, char *version, loader_shlibfunc_t *farray, int numf, void *autoinit_arg)
oai's avatar
oai committed
118
{
119 120 121 122 123 124 125 126 127
  void *lib_handle = NULL;
  initfunc_t fpi;
  checkverfunc_t fpc;
  getfarrayfunc_t fpg;
  char *shlib_path = NULL;
  char *afname = NULL;
  int ret = 0;
  int lib_idx = -1;

128 129 130 131
  if (!modname) {
    fprintf(stderr, "[LOADER] load_module_shlib(): no library name given\n");
    return -1;
  }
132 133 134 135

  if (!loader_data.shlibpath) {
     loader_init();
  }
136

137
  shlib_path = loader_format_shlibpath(modname, version);
138
  printf("shlib_path %s\n", shlib_path);
139

140 141 142 143 144 145 146 147 148 149 150
  for (int i = 0; i < loader_data.numshlibs; i++) {
    if (strcmp(loader_data.shlibs[i].name, modname) == 0) {
      printf("[LOADER] library %s has been loaded previously, reloading function pointers\n",
             shlib_path);
      lib_idx = i;
      break;
    }
  }
  if (lib_idx < 0) {
    lib_idx = loader_data.numshlibs;
    ++loader_data.numshlibs;
151
    if (loader_data.numshlibs > loader_data.maxshlibs) {
152
      fprintf(stderr, "[LOADER] can not load more than %u shlibs\n", loader_data.maxshlibs);
153 154 155
      ret = -1;
      goto load_module_shlib_exit;
    }
156 157 158
    loader_data.shlibs[lib_idx].name = strdup(modname);
    loader_data.shlibs[lib_idx].thisshlib_path = strdup(shlib_path);
  }
oai's avatar
oai committed
159

160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
  lib_handle = dlopen(shlib_path, RTLD_LAZY|RTLD_NODELETE|RTLD_GLOBAL);
  if (!lib_handle) {
    fprintf(stderr,"[LOADER] library %s is not loaded: %s\n", shlib_path,dlerror());
    ret = -1;
    goto load_module_shlib_exit;
  }

  printf("[LOADER] library %s successfully loaded\n", shlib_path);
  afname = malloc(strlen(modname)+15);
  if (!afname) {
    fprintf(stderr, "[LOADER] unable to allocate memory for library %s\n", shlib_path);
    ret = -1;
    goto load_module_shlib_exit;
  }
  sprintf(afname,"%s_checkbuildver",modname);
  fpc = dlsym(lib_handle,afname);
  if (fpc) {
    int chkver_ret = fpc(loader_data.mainexec_buildversion,
                         &(loader_data.shlibs[lib_idx].shlib_buildversion));
179 180 181 182 183 184
    if (chkver_ret < 0) {
      fprintf(stderr, "[LOADER]  %s %d lib %s, version mismatch",
              __FILE__, __LINE__, modname);
      ret = -1;
      goto load_module_shlib_exit;
    }
185 186 187 188 189 190 191
  }
  sprintf(afname,"%s_autoinit",modname);
  fpi = dlsym(lib_handle,afname);

  if (fpi) {
    fpi(autoinit_arg);
  }
192

193
  if (farray) {
194 195 196 197
    loader_shlibdesc_t *shlib = &loader_data.shlibs[lib_idx];
    if (!shlib->funcarray) {
      shlib->funcarray = calloc(numf, sizeof(loader_shlibfunc_t));
      if (!shlib->funcarray) {
198 199 200 201
        fprintf(stderr, "[LOADER] load_module_shlib(): unable to allocate memory\n");
        ret = -1;
        goto load_module_shlib_exit;
      }
202 203
      shlib->len_funcarray = numf;
      shlib->numfunc = 0;
204 205 206
    }
    for (int i = 0; i < numf; i++) {
      farray[i].fptr = dlsym(lib_handle,farray[i].fname);
207 208 209 210 211 212
      if (!farray[i].fptr) {
        fprintf(stderr, "[LOADER] load_module_shlib(): function %s not found: %s\n",
                  farray[i].fname, dlerror());
        ret = -1;
        goto load_module_shlib_exit;
      }
213 214 215 216 217 218 219 220 221 222 223 224 225
      /* check whether this function has been loaded before */
      int j = 0;
      for (; j < shlib->numfunc; ++j) {
        if (shlib->funcarray[j].fptr == farray[i].fptr) {
          int rc = strcmp(shlib->funcarray[i].fname, farray[i].fname);
          AssertFatal(rc == 0,
                      "reloading the same fptr with different fnames (%s, %s)\n",
                      shlib->funcarray[i].fname, farray[i].fname);
          break;
        }
      }
      if (j == shlib->numfunc) {
        if (shlib->numfunc == shlib->len_funcarray) {
226
          loader_shlibfunc_t *n = realloc(shlib->funcarray, shlib->numfunc * 2 * sizeof(loader_shlibfunc_t));
227 228 229 230 231 232 233 234 235 236 237 238
          if (!n) {
            fprintf(stderr, "[LOADER] %s(): unable to allocate memory\n", __func__);
            ret = -1;
            goto load_module_shlib_exit;
          }
          shlib->funcarray = n;
          shlib->len_funcarray = shlib->numfunc * 2;
        }
        shlib->funcarray[j].fname = strdup(farray[i].fname);
        shlib->funcarray[j].fptr = farray[i].fptr;
        shlib->numfunc++;
      }
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    } /* for int i... */
  } else {  /* farray ! NULL */
    sprintf(afname,"%s_getfarray",modname);
    fpg = dlsym(lib_handle,afname);
    if (fpg) {
      loader_data.shlibs[lib_idx].numfunc =
          fpg(&(loader_data.shlibs[lib_idx].funcarray));
    }
  } /* farray ! NULL */

load_module_shlib_exit:
  if (shlib_path) free(shlib_path);
  if (afname)     free(afname);
  if (lib_handle) dlclose(lib_handle);
  return ret;
oai's avatar
oai committed
254
}
255 256 257 258 259 260 261 262 263 264 265 266 267 268

void * get_shlibmodule_fptr(char *modname, char *fname)
{
    for (int i=0; i<loader_data.numshlibs && loader_data.shlibs[i].name != NULL; i++) {
        if ( strcmp(loader_data.shlibs[i].name, modname) == 0) {
            for (int j =0; j<loader_data.shlibs[i].numfunc ; j++) {
                 if (strcmp(loader_data.shlibs[i].funcarray[j].fname, fname) == 0) {
                     return loader_data.shlibs[i].funcarray[j].fptr;
                 }
            } /* for j loop on module functions*/
        }
    } /* for i loop on modules */
    return NULL;
}
269 270 271 272 273 274 275 276 277 278 279 280 281

void loader_reset()
{
  for (int i = 0; i < loader_data.numshlibs && loader_data.shlibs[i].name != NULL; i++) {
    loader_shlibdesc_t *shlib = &loader_data.shlibs[i];
    free(shlib->name);
    free(shlib->thisshlib_path);
    for (int j = 0; j < shlib->numfunc; ++j)
      free(shlib->funcarray[j].fname);
    free(shlib->funcarray);
    shlib->numfunc = 0;
    shlib->len_funcarray = 0;
  }
laurent's avatar
laurent committed
282 283 284 285
  if(loader_data.shlibpath){
    free(loader_data.shlibpath);
    loader_data.shlibpath=NULL;
  }
286 287
  free(loader_data.shlibs);
}