|
|
1.1.1.2 ! root 1: /* $Id: module.c,v 1.5 2003/08/23 13:48:30 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.2 ! root 37: _TME_RCSID("$Id: module.c,v 1.5 2003/08/23 13:48:30 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: */ 110: for (pass = 0; ++pass < 2; ) { 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 root 217: unsigned int tokens_count; 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++) { 233: if (!isalnum(c)) { 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); 1.1.1.2 ! root 299: tme_free_string_array(tokens, -1); 1.1 root 300: return (ENOENT); 301: } 302: 303: /* if there are three tokens, the module basename is the second, 304: else it is the same as the raw module name: */ 305: module_basename = (tokens_count == 3 306: ? tokens[1] 307: : tokens[0]); 308: 309: /* form the real module pathname: */ 310: module_pathname = tme_renew(char, 311: modules_dir, 312: strlen(modules_dir) 313: + strlen(module_basename) 314: + 1); 315: strcat(module_pathname, module_basename); 316: 317: /* dlopen the module: */ 318: tme_mutex_lock(&_tme_module_mutex); 319: handle = lt_dlopenext(module_pathname); 320: tme_mutex_unlock(&_tme_module_mutex); 1.1.1.2 ! root 321: tme_free(module_pathname); 1.1 root 322: if (handle == NULL) { 323: tme_output_append_error(_output, module_fake_pathname); 1.1.1.2 ! root 324: tme_free_string_array(tokens, -1); 1.1 root 325: return (ENOENT); 326: } 327: 328: /* return the new module: */ 329: module = tme_new(struct tme_module, 1); 330: module->tme_module_dlhandle = handle; 331: module->tme_module_submodule = (tokens_count == 3 332: ? tme_strdup(tokens[2]) 333: : NULL); 334: *_module = module; 1.1.1.2 ! root 335: tme_free_string_array(tokens, -1); 1.1 root 336: return (TME_OK); 337: } 338: 339: /* this looks up a symbol: */ 340: void * 341: tme_module_symbol(void *_module, const char *symbol) 342: { 343: struct tme_module *module; 344: char *module_symbol; 345: lt_ptr address; 346: 347: /* recover the module: */ 348: module = (struct tme_module *) _module; 349: 350: /* form the symbol to look up: */ 351: if (module->tme_module_submodule == NULL) { 352: module_symbol = tme_strdup(symbol); 353: } 354: else { 355: module_symbol = tme_new(char, 356: strlen(module->tme_module_submodule) 357: /* an underscore: */ 358: + 1 359: + strlen(symbol) 360: /* a NUL: */ 361: + 1); 362: sprintf(module_symbol, 363: "%s_%s", 364: module->tme_module_submodule, 365: symbol); 366: } 367: 368: /* look up the symbol: */ 369: tme_mutex_lock(&_tme_module_mutex); 370: address = lt_dlsym(module->tme_module_dlhandle, module_symbol); 371: tme_mutex_unlock(&_tme_module_mutex); 372: tme_free(module_symbol); 373: return (address); 374: } 375: 376: /* this immediately closes a module: */ 377: int 378: tme_module_close(void *_module) 379: { 380: struct tme_module *module; 381: int rc; 382: 383: /* recover the module: */ 384: module = (struct tme_module *) _module; 385: 386: /* close the module: */ 387: tme_mutex_lock(&_tme_module_mutex); 388: rc = lt_dlclose(module->tme_module_dlhandle); 389: tme_mutex_unlock(&_tme_module_mutex); 390: 391: /* free our structure: */ 392: if (module->tme_module_submodule != NULL) { 393: tme_free(module->tme_module_submodule); 394: } 395: tme_free(module); 396: 397: /* XXX assume success: */ 398: return (TME_OK); 399: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.