Annotation of tme/libtme/module.c, revision 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.