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