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