Annotation of tme/libtme/module.c, revision 1.1.1.6

1.1.1.5   root        1: /* $Id: module.c,v 1.10 2010/06/05 19:04:42 fredette Exp $ */
1.1       root        2: 
                      3: /* libtme/module.c - module management: */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2003 Matt Fredette
                      7:  * All rights reserved.
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *      This product includes software developed by Matt Fredette.
                     20:  * 4. The name of the author may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
                     25:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     26:  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
                     27:  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
                     28:  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
                     29:  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
                     31:  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
                     32:  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     33:  * POSSIBILITY OF SUCH DAMAGE.
                     34:  */
                     35: 
                     36: #include <tme/common.h>
1.1.1.5   root       37: _TME_RCSID("$Id: module.c,v 1.10 2010/06/05 19:04:42 fredette Exp $");
1.1       root       38: 
                     39: /* includes: */
                     40: #include <tme/threads.h>
                     41: #include <tme/module.h>
                     42: #include <tme/log.h>
1.1.1.2   root       43: #include <tme/misc.h>
1.1       root       44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <ctype.h>
                     47: #include <string.h>
                     48: #include <ltdl.h>
                     49: #include <shlibvar.h>
                     50: 
1.1.1.2   root       51: /* the libtool 1.5 used in tme development is supposed to add code to
                     52:    configure that decides whether to use an already-installed libltdl
                     53:    instead of the libltdl that comes with tme.  unfortunately, on some
                     54:    systems it appears to decide to use an installed libltdl without
                     55:    checking that the installed ltdl.h is recent enough to define
                     56:    lt_ptr.  we try to compensate for this here: */
                     57: #ifndef lt_ptr
                     58: #ifdef lt_ptr_t
                     59: #define lt_ptr lt_ptr_t
                     60: #else  /* !lt_ptr_t */
                     61: #error "installed libtool is too old"
                     62: #endif /* !lt_ptr_t */
                     63: #endif /* !lt_ptr */
                     64: 
1.1.1.5   root       65: /* similarly, the installed libltdl may be so recent that its ltdl.h
                     66:    renames lt_preloaded_symbols with a macro, to a name different from
                     67:    what our libtool script makes.  it's possible that the renaming
                     68:    macro is meant to be undefined to handle this problem: */
                     69: #undef lt_preloaded_symbols
                     70: 
1.1       root       71: /* types: */
                     72: struct tme_module {
                     73: 
                     74:   /* the next module on a list: */
                     75:   struct tme_module *tme_module_next;
                     76: 
                     77:   /* the libltdl handle for this module: */
                     78:   lt_dlhandle tme_module_dlhandle;
                     79: 
                     80:   /* any "submodule" symbol prefix: */
                     81:   char *tme_module_submodule;
                     82: };
                     83: 
                     84: /* globals: */
                     85: static tme_mutex_t _tme_module_mutex;
                     86: 
                     87: /* this initializes modules: */
                     88: int
                     89: tme_module_init(void)
                     90: {
                     91:   int rc;
                     92:   tme_mutex_init(&_tme_module_mutex);
                     93:   LTDL_SET_PRELOADED_SYMBOLS();
                     94:   rc = lt_dlinit();
                     95:   if (rc != 0) {
                     96:     return (EINVAL);
                     97:   }
                     98:   return (TME_OK);
                     99: }
                    100: 
                    101: /* this finds a modules directory: */
                    102: static FILE *
                    103: _tme_modules_find(const char *top_name,
                    104:                  unsigned int top_name_length,
                    105:                  char **_modules_dir)
                    106: {
                    107:   unsigned int modules_dir_length;
                    108:   int pass;
                    109:   const char *search_path;
                    110:   const char *p1, *p2, *p3;
                    111:   char c;
                    112:   char *modules_index_pathname;
                    113:   FILE *modules_index;
                    114: 
                    115:   /* pass over the search path environment variables: */
1.1.1.4   root      116:   for (pass = 0; ++pass <= 2; ) {
1.1       root      117: 
                    118:     /* get the next search path environment variable value: */
                    119:     search_path = NULL;
                    120:     switch (pass) {
                    121:     case 1: search_path = getenv("LTDL_LIBRARY_PATH"); break;
                    122:     case 2: search_path = getenv(LTDL_SHLIBPATH_VAR); break;
                    123:     default: assert(FALSE);
                    124:     }
                    125:     if (search_path == NULL) {
                    126:       continue;
                    127:     }
                    128: 
                    129:     /* take apart this module path: */
                    130:     p1 = p2 = search_path;
                    131:     for (p3 = search_path;; p3++) {
                    132: 
                    133:       /* get the next character: */
                    134:       c = *p3;
                    135: 
                    136:       /* continue if this is not a delimiter, tracking the last
                    137:          non-slash: */
                    138:       if (c != ':'
                    139:          && c != '\0') {
                    140:        if (c != '/') {
                    141:          p2 = p3;
                    142:        }
                    143:        continue;
                    144:       }
                    145: 
                    146:       /* if this path is absolute: */
                    147:       if (*p1 == '/') {
                    148: 
                    149:        /* form the modules index pathname to try, remembering what
                    150:           part of it is the modules directory pathname: */
                    151:        modules_dir_length = 
                    152:          /* the search path part, less any trailing slashes: */
                    153:          (p2 - p1) + 1
                    154:          /* a slash: */
                    155:          + 1
                    156:          + top_name_length
                    157:          /* a slash: */
                    158:          + 1;
                    159:        modules_index_pathname =
                    160:          tme_new(char,
                    161:                  modules_dir_length
                    162:                  + top_name_length
                    163:                  + strlen("-plugins.txt")
                    164:                  /* a NUL: */
                    165:                  + 1);
                    166:        memcpy(modules_index_pathname, p1, (p2 - p1) + 1);
                    167:        modules_index_pathname[(p2 - p1) + 1] = '/';
                    168:        memcpy(modules_index_pathname
                    169:               + (p2 - p1) + 1
                    170:               + 1,
                    171:               top_name,
                    172:               top_name_length);
                    173:        modules_index_pathname[((p2 - p1) + 1
                    174:                                + 1
                    175:                                + top_name_length)] = '/';
                    176:        memcpy(modules_index_pathname
                    177:               + modules_dir_length,
                    178:               top_name,
                    179:               top_name_length);
                    180:        strcpy(modules_index_pathname
                    181:               + modules_dir_length
                    182:               + top_name_length,
                    183:               "-plugins.txt");
                    184:        
                    185:        /* try to open the modules index: */
                    186:        modules_index = fopen(modules_index_pathname, "r");
                    187: 
                    188:        /* if we opened it, we're done: */
                    189:        if (modules_index != NULL) {
                    190:          modules_index_pathname[modules_dir_length] = '\0';
                    191:          *_modules_dir = modules_index_pathname;
                    192:          return (modules_index);
                    193:        }
                    194: 
                    195:        /* keep trying: */
                    196:        tme_free(modules_index_pathname);
                    197:       }
                    198: 
                    199:       /* stop if this was the last path: */
                    200:       if (c == '\0') {
                    201:        break;
                    202:       }
                    203: 
                    204:       /* advance to the next path: */
                    205:       p1 = p2 = p3 + 1;
                    206:     }
                    207:   }
                    208: 
                    209:   /* this search failed: */
                    210:   return (NULL);
                    211: }
                    212: 
                    213: /* this opens a module: */
                    214: int
                    215: tme_module_open(const char *module_fake_pathname, void **_module, char **_output)
                    216: {
                    217:   char *module_raw_name;
1.1.1.2   root      218:   char *p1, c, *first_slash;
1.1       root      219:   FILE *modules_index;
                    220:   char *modules_dir;
                    221:   char line_buffer[1024];
1.1.1.2   root      222:   char **tokens;
1.1.1.4   root      223:   int tokens_count;
1.1       root      224:   char *module_basename;
                    225:   char *module_pathname;
                    226:   lt_dlhandle handle;
                    227:   struct tme_module *module;
                    228:   
                    229:   /* strip leading slashes from the fake module pathname: */
                    230:   for (; *module_fake_pathname == '/'; module_fake_pathname++);
                    231: 
                    232:   /* turn all of the non-alphanumerics in the fake module pathname
                    233:      into underscores, and remember where the first slash was: */
                    234:   module_raw_name = tme_strdup(module_fake_pathname);
                    235:   first_slash = NULL;
                    236:   for (p1 = module_raw_name;
                    237:        (c = *p1) != '\0';
                    238:        p1++) {
1.1.1.4   root      239:     if (!isalnum((unsigned char) c)) {
1.1       root      240:       *p1 = '_';
                    241:       if (c == '/'
                    242:          && first_slash == NULL) {
                    243:        first_slash = p1;
                    244:       }
                    245:     }
                    246:   }
                    247: 
                    248:   /* if there were no slashes in the fake module pathname, there is no
                    249:      top name, which is incorrect: */
                    250:   if (first_slash == NULL) {
1.1.1.6 ! root      251:     tme_output_append_error(_output, "%s", module_fake_pathname);
1.1       root      252:     tme_free(module_raw_name);
                    253:     return (EINVAL);
                    254:   }
                    255: 
                    256:   /* open the modules index for this top name: */
                    257:   modules_index = _tme_modules_find(module_raw_name, 
                    258:                                    (first_slash - module_raw_name),
                    259:                                    &modules_dir);
                    260:   if (modules_index == NULL) {
1.1.1.6 ! root      261:     tme_output_append_error(_output, "%s", module_fake_pathname);
1.1       root      262:     tme_free(module_raw_name);
                    263:     return (ENOENT);
                    264:   }
                    265: 
                    266:   /* find the requested module in the index: */
1.1.1.2   root      267:   tokens = NULL;
1.1       root      268:   for (;;) {
                    269: 
                    270:     /* get the next line from the index: */
                    271:     tokens_count = 0;
                    272:     if (fgets(line_buffer, sizeof(line_buffer) - 1, modules_index) == NULL) {
                    273:       break;
                    274:     }
                    275:     line_buffer[sizeof(line_buffer) - 1] = '\0';
                    276:     if ((p1 = strchr(line_buffer, '\n')) != NULL) {
                    277:       *p1 = '\0';
                    278:     }
                    279: 
1.1.1.2   root      280:     /* tokenize this line: */
                    281:     tokens = tme_misc_tokenize(line_buffer, '#', &tokens_count);
1.1       root      282: 
                    283:     /* there must be either one or three tokens, and the first
                    284:        token must match the raw module name: */
                    285:     if ((tokens_count == 1
                    286:         || tokens_count == 3)
                    287:        && !strcmp(tokens[0], module_raw_name)) {
                    288:       break;
                    289:     }
1.1.1.2   root      290: 
                    291:     /* free the bad tokens: */
                    292:     tme_free_string_array(tokens, -1);
1.1       root      293:   }
                    294: 
                    295:   /* close the index: */
                    296:   fclose(modules_index);
                    297: 
                    298:   /* we no longer need the module raw name: */
                    299:   tme_free(module_raw_name);
                    300: 
                    301:   /* if we didn't find the module in the index: */
                    302:   if (tokens_count == 0) {
1.1.1.6 ! root      303:     tme_output_append_error(_output, "%s", module_fake_pathname);
1.1       root      304:     tme_free(modules_dir);
                    305:     return (ENOENT);
                    306:   }
                    307: 
                    308:   /* if there are three tokens, the module basename is the second,
                    309:      else it is the same as the raw module name: */
                    310:   module_basename = (tokens_count == 3
                    311:                     ? tokens[1]
                    312:                     : tokens[0]);
                    313:   
                    314:   /* form the real module pathname: */
                    315:   module_pathname = tme_renew(char,
                    316:                              modules_dir,
                    317:                              strlen(modules_dir)
                    318:                              + strlen(module_basename)
                    319:                              + 1);
                    320:   strcat(module_pathname, module_basename);
                    321:   
                    322:   /* dlopen the module: */
                    323:   tme_mutex_lock(&_tme_module_mutex);
                    324:   handle = lt_dlopenext(module_pathname);
                    325:   tme_mutex_unlock(&_tme_module_mutex);
1.1.1.2   root      326:   tme_free(module_pathname);
1.1       root      327:   if (handle == NULL) {
1.1.1.6 ! root      328:     tme_output_append_error(_output, "%s", module_fake_pathname);
1.1.1.2   root      329:     tme_free_string_array(tokens, -1);
1.1       root      330:     return (ENOENT);
                    331:   }
                    332: 
                    333:   /* return the new module: */
                    334:   module = tme_new(struct tme_module, 1);
                    335:   module->tme_module_dlhandle = handle;
                    336:   module->tme_module_submodule = (tokens_count == 3
                    337:                                  ? tme_strdup(tokens[2])
                    338:                                  : NULL);
                    339:   *_module = module;
1.1.1.2   root      340:   tme_free_string_array(tokens, -1);
1.1       root      341:   return (TME_OK);
                    342: }
                    343: 
                    344: /* this looks up a symbol: */
                    345: void *
                    346: tme_module_symbol(void *_module, const char *symbol)
                    347: {
                    348:   struct tme_module *module;
                    349:   char *module_symbol;
                    350:   lt_ptr address;
                    351: 
                    352:   /* recover the module: */
                    353:   module = (struct tme_module *) _module;
                    354: 
                    355:   /* form the symbol to look up: */
                    356:   if (module->tme_module_submodule == NULL) {
                    357:     module_symbol = tme_strdup(symbol);
                    358:   }
                    359:   else {
                    360:     module_symbol = tme_new(char, 
                    361:                            strlen(module->tme_module_submodule)
                    362:                            /* an underscore: */
                    363:                            + 1
                    364:                            + strlen(symbol)
                    365:                            /* a NUL: */
                    366:                            + 1);
                    367:     sprintf(module_symbol,
                    368:            "%s_%s", 
                    369:            module->tme_module_submodule,
                    370:            symbol);
                    371:   }
                    372:     
                    373:   /* look up the symbol: */
                    374:   tme_mutex_lock(&_tme_module_mutex);
                    375:   address = lt_dlsym(module->tme_module_dlhandle, module_symbol);
                    376:   tme_mutex_unlock(&_tme_module_mutex);
                    377:   tme_free(module_symbol);
                    378:   return (address);
                    379: }
                    380: 
                    381: /* this immediately closes a module: */
                    382: int
                    383: tme_module_close(void *_module)
                    384: {
                    385:   struct tme_module *module;
                    386:   int rc;
                    387: 
                    388:   /* recover the module: */
                    389:   module = (struct tme_module *) _module;
                    390: 
                    391:   /* close the module: */
                    392:   tme_mutex_lock(&_tme_module_mutex);
                    393:   rc = lt_dlclose(module->tme_module_dlhandle);
                    394:   tme_mutex_unlock(&_tme_module_mutex);
                    395: 
                    396:   /* free our structure: */
                    397:   if (module->tme_module_submodule != NULL) {
                    398:     tme_free(module->tme_module_submodule);
                    399:   }
                    400:   tme_free(module);
                    401: 
                    402:   /* XXX assume success: */
                    403:   return (TME_OK);
                    404: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.