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

1.1.1.4 ! root        1: /* $Id: module.c,v 1.9 2007/02/21 01:31:12 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.4 ! root       37: _TME_RCSID("$Id: module.c,v 1.9 2007/02/21 01:31:12 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       root       65: /* types: */
                     66: struct tme_module {
                     67: 
                     68:   /* the next module on a list: */
                     69:   struct tme_module *tme_module_next;
                     70: 
                     71:   /* the libltdl handle for this module: */
                     72:   lt_dlhandle tme_module_dlhandle;
                     73: 
                     74:   /* any "submodule" symbol prefix: */
                     75:   char *tme_module_submodule;
                     76: };
                     77: 
                     78: /* globals: */
                     79: static tme_mutex_t _tme_module_mutex;
                     80: 
                     81: /* this initializes modules: */
                     82: int
                     83: tme_module_init(void)
                     84: {
                     85:   int rc;
                     86:   tme_mutex_init(&_tme_module_mutex);
                     87:   LTDL_SET_PRELOADED_SYMBOLS();
                     88:   rc = lt_dlinit();
                     89:   if (rc != 0) {
                     90:     return (EINVAL);
                     91:   }
                     92:   return (TME_OK);
                     93: }
                     94: 
                     95: /* this finds a modules directory: */
                     96: static FILE *
                     97: _tme_modules_find(const char *top_name,
                     98:                  unsigned int top_name_length,
                     99:                  char **_modules_dir)
                    100: {
                    101:   unsigned int modules_dir_length;
                    102:   int pass;
                    103:   const char *search_path;
                    104:   const char *p1, *p2, *p3;
                    105:   char c;
                    106:   char *modules_index_pathname;
                    107:   FILE *modules_index;
                    108: 
                    109:   /* pass over the search path environment variables: */
1.1.1.4 ! root      110:   for (pass = 0; ++pass <= 2; ) {
1.1       root      111: 
                    112:     /* get the next search path environment variable value: */
                    113:     search_path = NULL;
                    114:     switch (pass) {
                    115:     case 1: search_path = getenv("LTDL_LIBRARY_PATH"); break;
                    116:     case 2: search_path = getenv(LTDL_SHLIBPATH_VAR); break;
                    117:     default: assert(FALSE);
                    118:     }
                    119:     if (search_path == NULL) {
                    120:       continue;
                    121:     }
                    122: 
                    123:     /* take apart this module path: */
                    124:     p1 = p2 = search_path;
                    125:     for (p3 = search_path;; p3++) {
                    126: 
                    127:       /* get the next character: */
                    128:       c = *p3;
                    129: 
                    130:       /* continue if this is not a delimiter, tracking the last
                    131:          non-slash: */
                    132:       if (c != ':'
                    133:          && c != '\0') {
                    134:        if (c != '/') {
                    135:          p2 = p3;
                    136:        }
                    137:        continue;
                    138:       }
                    139: 
                    140:       /* if this path is absolute: */
                    141:       if (*p1 == '/') {
                    142: 
                    143:        /* form the modules index pathname to try, remembering what
                    144:           part of it is the modules directory pathname: */
                    145:        modules_dir_length = 
                    146:          /* the search path part, less any trailing slashes: */
                    147:          (p2 - p1) + 1
                    148:          /* a slash: */
                    149:          + 1
                    150:          + top_name_length
                    151:          /* a slash: */
                    152:          + 1;
                    153:        modules_index_pathname =
                    154:          tme_new(char,
                    155:                  modules_dir_length
                    156:                  + top_name_length
                    157:                  + strlen("-plugins.txt")
                    158:                  /* a NUL: */
                    159:                  + 1);
                    160:        memcpy(modules_index_pathname, p1, (p2 - p1) + 1);
                    161:        modules_index_pathname[(p2 - p1) + 1] = '/';
                    162:        memcpy(modules_index_pathname
                    163:               + (p2 - p1) + 1
                    164:               + 1,
                    165:               top_name,
                    166:               top_name_length);
                    167:        modules_index_pathname[((p2 - p1) + 1
                    168:                                + 1
                    169:                                + top_name_length)] = '/';
                    170:        memcpy(modules_index_pathname
                    171:               + modules_dir_length,
                    172:               top_name,
                    173:               top_name_length);
                    174:        strcpy(modules_index_pathname
                    175:               + modules_dir_length
                    176:               + top_name_length,
                    177:               "-plugins.txt");
                    178:        
                    179:        /* try to open the modules index: */
                    180:        modules_index = fopen(modules_index_pathname, "r");
                    181: 
                    182:        /* if we opened it, we're done: */
                    183:        if (modules_index != NULL) {
                    184:          modules_index_pathname[modules_dir_length] = '\0';
                    185:          *_modules_dir = modules_index_pathname;
                    186:          return (modules_index);
                    187:        }
                    188: 
                    189:        /* keep trying: */
                    190:        tme_free(modules_index_pathname);
                    191:       }
                    192: 
                    193:       /* stop if this was the last path: */
                    194:       if (c == '\0') {
                    195:        break;
                    196:       }
                    197: 
                    198:       /* advance to the next path: */
                    199:       p1 = p2 = p3 + 1;
                    200:     }
                    201:   }
                    202: 
                    203:   /* this search failed: */
                    204:   return (NULL);
                    205: }
                    206: 
                    207: /* this opens a module: */
                    208: int
                    209: tme_module_open(const char *module_fake_pathname, void **_module, char **_output)
                    210: {
                    211:   char *module_raw_name;
1.1.1.2   root      212:   char *p1, c, *first_slash;
1.1       root      213:   FILE *modules_index;
                    214:   char *modules_dir;
                    215:   char line_buffer[1024];
1.1.1.2   root      216:   char **tokens;
1.1.1.4 ! root      217:   int tokens_count;
1.1       root      218:   char *module_basename;
                    219:   char *module_pathname;
                    220:   lt_dlhandle handle;
                    221:   struct tme_module *module;
                    222:   
                    223:   /* strip leading slashes from the fake module pathname: */
                    224:   for (; *module_fake_pathname == '/'; module_fake_pathname++);
                    225: 
                    226:   /* turn all of the non-alphanumerics in the fake module pathname
                    227:      into underscores, and remember where the first slash was: */
                    228:   module_raw_name = tme_strdup(module_fake_pathname);
                    229:   first_slash = NULL;
                    230:   for (p1 = module_raw_name;
                    231:        (c = *p1) != '\0';
                    232:        p1++) {
1.1.1.4 ! root      233:     if (!isalnum((unsigned char) c)) {
1.1       root      234:       *p1 = '_';
                    235:       if (c == '/'
                    236:          && first_slash == NULL) {
                    237:        first_slash = p1;
                    238:       }
                    239:     }
                    240:   }
                    241: 
                    242:   /* if there were no slashes in the fake module pathname, there is no
                    243:      top name, which is incorrect: */
                    244:   if (first_slash == NULL) {
                    245:     tme_output_append_error(_output, module_fake_pathname);
                    246:     tme_free(module_raw_name);
                    247:     return (EINVAL);
                    248:   }
                    249: 
                    250:   /* open the modules index for this top name: */
                    251:   modules_index = _tme_modules_find(module_raw_name, 
                    252:                                    (first_slash - module_raw_name),
                    253:                                    &modules_dir);
                    254:   if (modules_index == NULL) {
                    255:     tme_output_append_error(_output, module_fake_pathname);
                    256:     tme_free(module_raw_name);
                    257:     return (ENOENT);
                    258:   }
                    259: 
                    260:   /* find the requested module in the index: */
1.1.1.2   root      261:   tokens = NULL;
1.1       root      262:   for (;;) {
                    263: 
                    264:     /* get the next line from the index: */
                    265:     tokens_count = 0;
                    266:     if (fgets(line_buffer, sizeof(line_buffer) - 1, modules_index) == NULL) {
                    267:       break;
                    268:     }
                    269:     line_buffer[sizeof(line_buffer) - 1] = '\0';
                    270:     if ((p1 = strchr(line_buffer, '\n')) != NULL) {
                    271:       *p1 = '\0';
                    272:     }
                    273: 
1.1.1.2   root      274:     /* tokenize this line: */
                    275:     tokens = tme_misc_tokenize(line_buffer, '#', &tokens_count);
1.1       root      276: 
                    277:     /* there must be either one or three tokens, and the first
                    278:        token must match the raw module name: */
                    279:     if ((tokens_count == 1
                    280:         || tokens_count == 3)
                    281:        && !strcmp(tokens[0], module_raw_name)) {
                    282:       break;
                    283:     }
1.1.1.2   root      284: 
                    285:     /* free the bad tokens: */
                    286:     tme_free_string_array(tokens, -1);
1.1       root      287:   }
                    288: 
                    289:   /* close the index: */
                    290:   fclose(modules_index);
                    291: 
                    292:   /* we no longer need the module raw name: */
                    293:   tme_free(module_raw_name);
                    294: 
                    295:   /* if we didn't find the module in the index: */
                    296:   if (tokens_count == 0) {
                    297:     tme_output_append_error(_output, module_fake_pathname);
                    298:     tme_free(modules_dir);
                    299:     return (ENOENT);
                    300:   }
                    301: 
                    302:   /* if there are three tokens, the module basename is the second,
                    303:      else it is the same as the raw module name: */
                    304:   module_basename = (tokens_count == 3
                    305:                     ? tokens[1]
                    306:                     : tokens[0]);
                    307:   
                    308:   /* form the real module pathname: */
                    309:   module_pathname = tme_renew(char,
                    310:                              modules_dir,
                    311:                              strlen(modules_dir)
                    312:                              + strlen(module_basename)
                    313:                              + 1);
                    314:   strcat(module_pathname, module_basename);
                    315:   
                    316:   /* dlopen the module: */
                    317:   tme_mutex_lock(&_tme_module_mutex);
                    318:   handle = lt_dlopenext(module_pathname);
                    319:   tme_mutex_unlock(&_tme_module_mutex);
1.1.1.2   root      320:   tme_free(module_pathname);
1.1       root      321:   if (handle == NULL) {
                    322:     tme_output_append_error(_output, module_fake_pathname);
1.1.1.2   root      323:     tme_free_string_array(tokens, -1);
1.1       root      324:     return (ENOENT);
                    325:   }
                    326: 
                    327:   /* return the new module: */
                    328:   module = tme_new(struct tme_module, 1);
                    329:   module->tme_module_dlhandle = handle;
                    330:   module->tme_module_submodule = (tokens_count == 3
                    331:                                  ? tme_strdup(tokens[2])
                    332:                                  : NULL);
                    333:   *_module = module;
1.1.1.2   root      334:   tme_free_string_array(tokens, -1);
1.1       root      335:   return (TME_OK);
                    336: }
                    337: 
                    338: /* this looks up a symbol: */
                    339: void *
                    340: tme_module_symbol(void *_module, const char *symbol)
                    341: {
                    342:   struct tme_module *module;
                    343:   char *module_symbol;
                    344:   lt_ptr address;
                    345: 
                    346:   /* recover the module: */
                    347:   module = (struct tme_module *) _module;
                    348: 
                    349:   /* form the symbol to look up: */
                    350:   if (module->tme_module_submodule == NULL) {
                    351:     module_symbol = tme_strdup(symbol);
                    352:   }
                    353:   else {
                    354:     module_symbol = tme_new(char, 
                    355:                            strlen(module->tme_module_submodule)
                    356:                            /* an underscore: */
                    357:                            + 1
                    358:                            + strlen(symbol)
                    359:                            /* a NUL: */
                    360:                            + 1);
                    361:     sprintf(module_symbol,
                    362:            "%s_%s", 
                    363:            module->tme_module_submodule,
                    364:            symbol);
                    365:   }
                    366:     
                    367:   /* look up the symbol: */
                    368:   tme_mutex_lock(&_tme_module_mutex);
                    369:   address = lt_dlsym(module->tme_module_dlhandle, module_symbol);
                    370:   tme_mutex_unlock(&_tme_module_mutex);
                    371:   tme_free(module_symbol);
                    372:   return (address);
                    373: }
                    374: 
                    375: /* this immediately closes a module: */
                    376: int
                    377: tme_module_close(void *_module)
                    378: {
                    379:   struct tme_module *module;
                    380:   int rc;
                    381: 
                    382:   /* recover the module: */
                    383:   module = (struct tme_module *) _module;
                    384: 
                    385:   /* close the module: */
                    386:   tme_mutex_lock(&_tme_module_mutex);
                    387:   rc = lt_dlclose(module->tme_module_dlhandle);
                    388:   tme_mutex_unlock(&_tme_module_mutex);
                    389: 
                    390:   /* free our structure: */
                    391:   if (module->tme_module_submodule != NULL) {
                    392:     tme_free(module->tme_module_submodule);
                    393:   }
                    394:   tme_free(module);
                    395: 
                    396:   /* XXX assume success: */
                    397:   return (TME_OK);
                    398: }

unix.superglobalmegacorp.com

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