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

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

unix.superglobalmegacorp.com

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