|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.