loadmod.c revision 1b5d61b8
1/* 2 * Copyright 1995-1998 by Metro Link, Inc. 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Metro Link, Inc. not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Metro Link, Inc. makes no 11 * representations about the suitability of this software for any purpose. 12 * It is provided "as is" without express or implied warranty. 13 * 14 * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22/* 23 * Copyright (c) 1997-2002 by The XFree86 Project, Inc. 24 * 25 * Permission is hereby granted, free of charge, to any person obtaining a 26 * copy of this software and associated documentation files (the "Software"), 27 * to deal in the Software without restriction, including without limitation 28 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 29 * and/or sell copies of the Software, and to permit persons to whom the 30 * Software is furnished to do so, subject to the following conditions: 31 * 32 * The above copyright notice and this permission notice shall be included in 33 * all copies or substantial portions of the Software. 34 * 35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 38 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 41 * OTHER DEALINGS IN THE SOFTWARE. 42 * 43 * Except as contained in this notice, the name of the copyright holder(s) 44 * and author(s) shall not be used in advertising or otherwise to promote 45 * the sale, use or other dealings in this Software without prior written 46 * authorization from the copyright holder(s) and author(s). 47 */ 48 49#ifdef HAVE_XORG_CONFIG_H 50#include <xorg-config.h> 51#endif 52 53#include "dix.h" 54#include "os.h" 55#include "loaderProcs.h" 56#include "xf86Module.h" 57#include "loader.h" 58 59#include <sys/stat.h> 60#include <sys/types.h> 61#include <regex.h> 62#include <dirent.h> 63#include <limits.h> 64 65typedef struct _pattern { 66 const char *pattern; 67 regex_t rex; 68} PatternRec, *PatternPtr; 69 70/* Prototypes for static functions */ 71static char *FindModule(const char *, const char *, PatternPtr); 72static Bool CheckVersion(const char *, XF86ModuleVersionInfo *, 73 const XF86ModReqInfo *); 74static char *LoaderGetCanonicalName(const char *, PatternPtr); 75static void RemoveChild(ModuleDescPtr); 76 77const ModuleVersions LoaderVersionInfo = { 78 XORG_VERSION_CURRENT, 79 ABI_ANSIC_VERSION, 80 ABI_VIDEODRV_VERSION, 81 ABI_XINPUT_VERSION, 82 ABI_EXTENSION_VERSION, 83}; 84 85static int ModuleDuplicated[] = { }; 86 87static void 88FreeStringList(char **paths) 89{ 90 char **p; 91 92 if (!paths) 93 return; 94 95 for (p = paths; *p; p++) 96 free(*p); 97 98 free(paths); 99} 100 101static char **defaultPathList = NULL; 102 103static Bool 104PathIsAbsolute(const char *path) 105{ 106 return *path == '/'; 107} 108 109/* 110 * Convert a comma-separated path into a NULL-terminated array of path 111 * elements, rejecting any that are not full absolute paths, and appending 112 * a '/' when it isn't already present. 113 */ 114static char ** 115InitPathList(const char *path) 116{ 117 char *fullpath = NULL; 118 char *elem = NULL; 119 char **list = NULL, **save = NULL; 120 int len; 121 int addslash; 122 int n = 0; 123 124 fullpath = strdup(path); 125 if (!fullpath) 126 return NULL; 127 elem = strtok(fullpath, ","); 128 while (elem) { 129 if (PathIsAbsolute(elem)) { 130 len = strlen(elem); 131 addslash = (elem[len - 1] != '/'); 132 if (addslash) 133 len++; 134 save = list; 135 list = reallocarray(list, n + 2, sizeof(char *)); 136 if (!list) { 137 if (save) { 138 save[n] = NULL; 139 FreeStringList(save); 140 } 141 free(fullpath); 142 return NULL; 143 } 144 list[n] = malloc(len + 1); 145 if (!list[n]) { 146 FreeStringList(list); 147 free(fullpath); 148 return NULL; 149 } 150 strcpy(list[n], elem); 151 if (addslash) { 152 list[n][len - 1] = '/'; 153 list[n][len] = '\0'; 154 } 155 n++; 156 } 157 elem = strtok(NULL, ","); 158 } 159 if (list) 160 list[n] = NULL; 161 free(fullpath); 162 return list; 163} 164 165void 166LoaderSetPath(const char *path) 167{ 168 if (!path) 169 return; 170 171 FreeStringList(defaultPathList); 172 defaultPathList = InitPathList(path); 173} 174 175/* Standard set of module subdirectories to search, in order of preference */ 176static const char *stdSubdirs[] = { 177 "", 178 "input/", 179 "drivers/", 180 "extensions/", 181 NULL 182}; 183 184/* 185 * Standard set of module name patterns to check, in order of preference 186 * These are regular expressions (suitable for use with POSIX regex(3)). 187 * 188 * This list assumes that you're an ELFish platform and therefore your 189 * shared libraries are named something.so. If we're ever nuts enough 190 * to port this DDX to, say, Darwin, we'll need to fix this. 191 */ 192static PatternRec stdPatterns[] = { 193#ifdef __CYGWIN__ 194 {"^cyg(.*)\\.dll$",}, 195 {"(.*)_drv\\.dll$",}, 196 {"(.*)\\.dll$",}, 197#else 198 {"^lib(.*)\\.so$",}, 199 {"(.*)_drv\\.so$",}, 200 {"(.*)\\.so$",}, 201#endif 202 {NULL,} 203}; 204 205static PatternPtr 206InitPatterns(const char **patternlist) 207{ 208 char errmsg[80]; 209 int i, e; 210 PatternPtr patterns = NULL; 211 PatternPtr p = NULL; 212 static int firstTime = 1; 213 const char **s; 214 215 if (firstTime) { 216 /* precompile stdPatterns */ 217 firstTime = 0; 218 for (p = stdPatterns; p->pattern; p++) 219 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 220 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 221 FatalError("InitPatterns: regcomp error for `%s': %s\n", 222 p->pattern, errmsg); 223 } 224 } 225 226 if (patternlist) { 227 for (i = 0, s = patternlist; *s; i++, s++) 228 if (*s == DEFAULT_LIST) 229 i += ARRAY_SIZE(stdPatterns) - 1 - 1; 230 patterns = xallocarray(i + 1, sizeof(PatternRec)); 231 if (!patterns) { 232 return NULL; 233 } 234 for (i = 0, s = patternlist; *s; i++, s++) 235 if (*s != DEFAULT_LIST) { 236 p = patterns + i; 237 p->pattern = *s; 238 if ((e = regcomp(&p->rex, p->pattern, REG_EXTENDED)) != 0) { 239 regerror(e, &p->rex, errmsg, sizeof(errmsg)); 240 ErrorF("InitPatterns: regcomp error for `%s': %s\n", 241 p->pattern, errmsg); 242 i--; 243 } 244 } 245 else { 246 for (p = stdPatterns; p->pattern; p++, i++) 247 patterns[i] = *p; 248 if (p != stdPatterns) 249 i--; 250 } 251 patterns[i].pattern = NULL; 252 } 253 else 254 patterns = stdPatterns; 255 return patterns; 256} 257 258static void 259FreePatterns(PatternPtr patterns) 260{ 261 if (patterns && patterns != stdPatterns) 262 free(patterns); 263} 264 265static char * 266FindModuleInSubdir(const char *dirpath, const char *module) 267{ 268 struct dirent *direntry = NULL; 269 DIR *dir = NULL; 270 char *ret = NULL, tmpBuf[PATH_MAX]; 271 struct stat stat_buf; 272 273 dir = opendir(dirpath); 274 if (!dir) 275 return NULL; 276 277 while ((direntry = readdir(dir))) { 278 if (direntry->d_name[0] == '.') 279 continue; 280 snprintf(tmpBuf, PATH_MAX, "%s%s/", dirpath, direntry->d_name); 281 /* the stat with the appended / fails for normal files, 282 and works for sub dirs fine, looks a bit strange in strace 283 but does seem to work */ 284 if ((stat(tmpBuf, &stat_buf) == 0) && S_ISDIR(stat_buf.st_mode)) { 285 if ((ret = FindModuleInSubdir(tmpBuf, module))) 286 break; 287 continue; 288 } 289 290#ifdef __CYGWIN__ 291 snprintf(tmpBuf, PATH_MAX, "cyg%s.dll", module); 292#else 293 snprintf(tmpBuf, PATH_MAX, "lib%s.so", module); 294#endif 295 if (strcmp(direntry->d_name, tmpBuf) == 0) { 296 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 297 ret = NULL; 298 break; 299 } 300 301#ifdef __CYGWIN__ 302 snprintf(tmpBuf, PATH_MAX, "%s_drv.dll", module); 303#else 304 snprintf(tmpBuf, PATH_MAX, "%s_drv.so", module); 305#endif 306 if (strcmp(direntry->d_name, tmpBuf) == 0) { 307 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 308 ret = NULL; 309 break; 310 } 311 312#ifdef __CYGWIN__ 313 snprintf(tmpBuf, PATH_MAX, "%s.dll", module); 314#else 315 snprintf(tmpBuf, PATH_MAX, "%s.so", module); 316#endif 317 if (strcmp(direntry->d_name, tmpBuf) == 0) { 318 if (asprintf(&ret, "%s%s", dirpath, tmpBuf) == -1) 319 ret = NULL; 320 break; 321 } 322 } 323 324 closedir(dir); 325 return ret; 326} 327 328static char * 329FindModule(const char *module, const char *dirname, PatternPtr patterns) 330{ 331 char buf[PATH_MAX + 1]; 332 char *name = NULL; 333 const char **s; 334 335 if (strlen(dirname) > PATH_MAX) 336 return NULL; 337 338 for (s = stdSubdirs; *s; s++) { 339 snprintf(buf, PATH_MAX, "%s%s", dirname, *s); 340 if ((name = FindModuleInSubdir(buf, module))) 341 break; 342 } 343 344 return name; 345} 346 347const char ** 348LoaderListDir(const char *subdir, const char **patternlist) 349{ 350 char buf[PATH_MAX + 1]; 351 char **pathlist; 352 char **elem; 353 PatternPtr patterns = NULL; 354 PatternPtr p; 355 DIR *d; 356 struct dirent *dp; 357 regmatch_t match[2]; 358 struct stat stat_buf; 359 int len, dirlen; 360 char *fp; 361 char **listing = NULL; 362 char **save; 363 char **ret = NULL; 364 int n = 0; 365 366 if (!(pathlist = defaultPathList)) 367 return NULL; 368 if (!(patterns = InitPatterns(patternlist))) 369 goto bail; 370 371 for (elem = pathlist; *elem; elem++) { 372 dirlen = snprintf(buf, PATH_MAX, "%s/%s", *elem, subdir); 373 fp = buf + dirlen; 374 if (stat(buf, &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode) && 375 (d = opendir(buf))) { 376 if (buf[dirlen - 1] != '/') { 377 buf[dirlen++] = '/'; 378 fp++; 379 } 380 while ((dp = readdir(d))) { 381 if (dirlen + strlen(dp->d_name) > PATH_MAX) 382 continue; 383 strcpy(fp, dp->d_name); 384 if (!(stat(buf, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode))) 385 continue; 386 for (p = patterns; p->pattern; p++) { 387 if (regexec(&p->rex, dp->d_name, 2, match, 0) == 0 && 388 match[1].rm_so != -1) { 389 len = match[1].rm_eo - match[1].rm_so; 390 save = listing; 391 listing = reallocarray(listing, n + 2, sizeof(char *)); 392 if (!listing) { 393 if (save) { 394 save[n] = NULL; 395 FreeStringList(save); 396 } 397 closedir(d); 398 goto bail; 399 } 400 listing[n] = malloc(len + 1); 401 if (!listing[n]) { 402 FreeStringList(listing); 403 closedir(d); 404 goto bail; 405 } 406 strncpy(listing[n], dp->d_name + match[1].rm_so, len); 407 listing[n][len] = '\0'; 408 n++; 409 break; 410 } 411 } 412 } 413 closedir(d); 414 } 415 } 416 if (listing) 417 listing[n] = NULL; 418 ret = listing; 419 420 bail: 421 FreePatterns(patterns); 422 return (const char **) ret; 423} 424 425static Bool 426CheckVersion(const char *module, XF86ModuleVersionInfo * data, 427 const XF86ModReqInfo * req) 428{ 429 int vercode[4]; 430 long ver = data->xf86version; 431 MessageType errtype; 432 433 LogMessage(X_INFO, "Module %s: vendor=\"%s\"\n", 434 data->modname ? data->modname : "UNKNOWN!", 435 data->vendor ? data->vendor : "UNKNOWN!"); 436 437 vercode[0] = ver / 10000000; 438 vercode[1] = (ver / 100000) % 100; 439 vercode[2] = (ver / 1000) % 100; 440 vercode[3] = ver % 1000; 441 LogWrite(1, "\tcompiled for %d.%d.%d", vercode[0], vercode[1], vercode[2]); 442 if (vercode[3] != 0) 443 LogWrite(1, ".%d", vercode[3]); 444 LogWrite(1, ", module version = %d.%d.%d\n", data->majorversion, 445 data->minorversion, data->patchlevel); 446 447 if (data->moduleclass) 448 LogWrite(2, "\tModule class: %s\n", data->moduleclass); 449 450 ver = -1; 451 if (data->abiclass) { 452 int abimaj, abimin; 453 int vermaj, vermin; 454 455 if (!strcmp(data->abiclass, ABI_CLASS_ANSIC)) 456 ver = LoaderVersionInfo.ansicVersion; 457 else if (!strcmp(data->abiclass, ABI_CLASS_VIDEODRV)) 458 ver = LoaderVersionInfo.videodrvVersion; 459 else if (!strcmp(data->abiclass, ABI_CLASS_XINPUT)) 460 ver = LoaderVersionInfo.xinputVersion; 461 else if (!strcmp(data->abiclass, ABI_CLASS_EXTENSION)) 462 ver = LoaderVersionInfo.extensionVersion; 463 464 abimaj = GET_ABI_MAJOR(data->abiversion); 465 abimin = GET_ABI_MINOR(data->abiversion); 466 LogWrite(2, "\tABI class: %s, version %d.%d\n", 467 data->abiclass, abimaj, abimin); 468 if (ver != -1) { 469 vermaj = GET_ABI_MAJOR(ver); 470 vermin = GET_ABI_MINOR(ver); 471 if (abimaj != vermaj) { 472 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 473 errtype = X_WARNING; 474 else 475 errtype = X_ERROR; 476 LogMessageVerb(errtype, 0, "%s: module ABI major version (%d) " 477 "doesn't match the server's version (%d)\n", 478 module, abimaj, vermaj); 479 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 480 return FALSE; 481 } 482 else if (abimin > vermin) { 483 if (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) 484 errtype = X_WARNING; 485 else 486 errtype = X_ERROR; 487 LogMessageVerb(errtype, 0, "%s: module ABI minor version (%d) " 488 "is newer than the server's version (%d)\n", 489 module, abimin, vermin); 490 if (!(LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL)) 491 return FALSE; 492 } 493 } 494 } 495 496 /* Check against requirements that the caller has specified */ 497 if (req) { 498 if (data->majorversion != req->majorversion) { 499 LogMessageVerb(X_WARNING, 2, "%s: module major version (%d) " 500 "doesn't match required major version (%d)\n", 501 module, data->majorversion, req->majorversion); 502 return FALSE; 503 } 504 else if (data->minorversion < req->minorversion) { 505 LogMessageVerb(X_WARNING, 2, "%s: module minor version (%d) is " 506 "less than the required minor version (%d)\n", 507 module, data->minorversion, req->minorversion); 508 return FALSE; 509 } 510 else if (data->minorversion == req->minorversion && 511 data->patchlevel < req->patchlevel) { 512 LogMessageVerb(X_WARNING, 2, "%s: module patch level (%d) " 513 "is less than the required patch level " 514 "(%d)\n", module, data->patchlevel, req->patchlevel); 515 return FALSE; 516 } 517 if (req->moduleclass) { 518 if (!data->moduleclass || 519 strcmp(req->moduleclass, data->moduleclass)) { 520 LogMessageVerb(X_WARNING, 2, "%s: Module class (%s) doesn't " 521 "match the required class (%s)\n", module, 522 data->moduleclass ? data->moduleclass : "<NONE>", 523 req->moduleclass); 524 return FALSE; 525 } 526 } 527 else if (req->abiclass != ABI_CLASS_NONE) { 528 if (!data->abiclass || strcmp(req->abiclass, data->abiclass)) { 529 LogMessageVerb(X_WARNING, 2, "%s: ABI class (%s) doesn't match" 530 " the required ABI class (%s)\n", module, 531 data->abiclass ? data->abiclass : "<NONE>", 532 req->abiclass); 533 return FALSE; 534 } 535 } 536 if (req->abiclass != ABI_CLASS_NONE) { 537 int reqmaj, reqmin, maj, min; 538 539 reqmaj = GET_ABI_MAJOR(req->abiversion); 540 reqmin = GET_ABI_MINOR(req->abiversion); 541 maj = GET_ABI_MAJOR(data->abiversion); 542 min = GET_ABI_MINOR(data->abiversion); 543 if (maj != reqmaj) { 544 LogMessageVerb(X_WARNING, 2, "%s: ABI major version (%d) " 545 "doesn't match the required ABI major version " 546 "(%d)\n", module, maj, reqmaj); 547 return FALSE; 548 } 549 /* XXX Maybe this should be the other way around? */ 550 if (min > reqmin) { 551 LogMessageVerb(X_WARNING, 2, "%s: module ABI minor version " 552 "(%d) is newer than that available (%d)\n", 553 module, min, reqmin); 554 return FALSE; 555 } 556 } 557 } 558 return TRUE; 559} 560 561static ModuleDescPtr 562AddSibling(ModuleDescPtr head, ModuleDescPtr new) 563{ 564 new->sib = head; 565 return new; 566} 567 568void * 569LoadSubModule(void *_parent, const char *module, 570 const char **subdirlist, const char **patternlist, 571 void *options, const XF86ModReqInfo * modreq, 572 int *errmaj, int *errmin) 573{ 574 ModuleDescPtr submod; 575 ModuleDescPtr parent = (ModuleDescPtr) _parent; 576 577 LogMessageVerb(X_INFO, 3, "Loading sub module \"%s\"\n", module); 578 579 if (PathIsAbsolute(module)) { 580 LogMessage(X_ERROR, "LoadSubModule: " 581 "Absolute module path not permitted: \"%s\"\n", module); 582 if (errmaj) 583 *errmaj = LDR_BADUSAGE; 584 if (errmin) 585 *errmin = 0; 586 return NULL; 587 } 588 589 submod = LoadModule(module, options, modreq, errmaj); 590 if (submod && submod != (ModuleDescPtr) 1) { 591 parent->child = AddSibling(parent->child, submod); 592 submod->parent = parent; 593 } 594 return submod; 595} 596 597ModuleDescPtr 598DuplicateModule(ModuleDescPtr mod, ModuleDescPtr parent) 599{ 600 ModuleDescPtr ret; 601 602 if (!mod) 603 return NULL; 604 605 ret = calloc(1, sizeof(ModuleDesc)); 606 if (ret == NULL) 607 return NULL; 608 609 ret->handle = mod->handle; 610 611 ret->SetupProc = mod->SetupProc; 612 ret->TearDownProc = mod->TearDownProc; 613 ret->TearDownData = ModuleDuplicated; 614 ret->child = DuplicateModule(mod->child, ret); 615 ret->sib = DuplicateModule(mod->sib, parent); 616 ret->parent = parent; 617 ret->VersionInfo = mod->VersionInfo; 618 619 return ret; 620} 621 622static const char *compiled_in_modules[] = { 623 "ddc", 624 "i2c", 625 "ramdac", 626 "dbe", 627 "record", 628 "extmod", 629 "dri", 630 "dri2", 631#ifdef DRI3 632 "dri3", 633#endif 634#ifdef PRESENT 635 "present", 636#endif 637 NULL 638}; 639 640/* 641 * LoadModule: load a module 642 * 643 * module The module name. Normally this is not a filename but the 644 * module's "canonical name. A full pathname is, however, 645 * also accepted. 646 * options A NULL terminated list of Options that are passed to the 647 * module's SetupProc function. 648 * modreq An optional XF86ModReqInfo* containing 649 * version/ABI/vendor-ABI requirements to check for when 650 * loading the module. The following fields of the 651 * XF86ModReqInfo struct are checked: 652 * majorversion - must match the module's majorversion exactly 653 * minorversion - the module's minorversion must be >= this 654 * patchlevel - the module's minorversion.patchlevel must be 655 * >= this. Patchlevel is ignored when 656 * minorversion is not set. 657 * abiclass - (string) must match the module's abiclass 658 * abiversion - must be consistent with the module's 659 * abiversion (major equal, minor no older) 660 * moduleclass - string must match the module's moduleclass 661 * string 662 * "don't care" values are ~0 for numbers, and NULL for strings 663 * errmaj Major error return. 664 * 665 */ 666ModuleDescPtr 667LoadModule(const char *module, void *options, const XF86ModReqInfo *modreq, 668 int *errmaj) 669{ 670 XF86ModuleData *initdata = NULL; 671 char **pathlist = NULL; 672 char *found = NULL; 673 char *name = NULL; 674 char **path_elem = NULL; 675 char *p = NULL; 676 ModuleDescPtr ret = NULL; 677 PatternPtr patterns = NULL; 678 int noncanonical = 0; 679 char *m = NULL; 680 const char **cim; 681 682 LogMessageVerb(X_INFO, 3, "LoadModule: \"%s\"", module); 683 684 patterns = InitPatterns(NULL); 685 name = LoaderGetCanonicalName(module, patterns); 686 noncanonical = (name && strcmp(module, name) != 0); 687 if (noncanonical) { 688 LogWrite(3, " (%s)\n", name); 689 LogMessageVerb(X_WARNING, 1, 690 "LoadModule: given non-canonical module name \"%s\"\n", 691 module); 692 m = name; 693 } 694 else { 695 LogWrite(3, "\n"); 696 m = (char *) module; 697 } 698 699 for (cim = compiled_in_modules; *cim; cim++) 700 if (!strcmp(m, *cim)) { 701 LogMessageVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); 702 ret = (ModuleDescPtr) 1; 703 goto LoadModule_exit; 704 } 705 706 if (!name) { 707 if (errmaj) 708 *errmaj = LDR_BADUSAGE; 709 goto LoadModule_fail; 710 } 711 ret = calloc(1, sizeof(ModuleDesc)); 712 if (!ret) { 713 if (errmaj) 714 *errmaj = LDR_NOMEM; 715 goto LoadModule_fail; 716 } 717 718 pathlist = defaultPathList; 719 if (!pathlist) { 720 /* This could be a malloc failure too */ 721 if (errmaj) 722 *errmaj = LDR_BADUSAGE; 723 goto LoadModule_fail; 724 } 725 726 /* 727 * if the module name is not a full pathname, we need to 728 * check the elements in the path 729 */ 730 if (PathIsAbsolute(module)) 731 found = xstrdup(module); 732 path_elem = pathlist; 733 while (!found && *path_elem != NULL) { 734 found = FindModule(m, *path_elem, patterns); 735 path_elem++; 736 /* 737 * When the module name isn't the canonical name, search for the 738 * former if no match was found for the latter. 739 */ 740 if (!*path_elem && m == name) { 741 path_elem = pathlist; 742 m = (char *) module; 743 } 744 } 745 746 /* 747 * did we find the module? 748 */ 749 if (!found) { 750 LogMessage(X_WARNING, "Warning, couldn't open module %s\n", module); 751 if (errmaj) 752 *errmaj = LDR_NOENT; 753 goto LoadModule_fail; 754 } 755 ret->handle = LoaderOpen(found, errmaj); 756 if (ret->handle == NULL) 757 goto LoadModule_fail; 758 759 /* drop any explicit suffix from the module name */ 760 p = strchr(name, '.'); 761 if (p) 762 *p = '\0'; 763 764 /* 765 * now check if the special data object <modulename>ModuleData is 766 * present. 767 */ 768 if (asprintf(&p, "%sModuleData", name) == -1) { 769 p = NULL; 770 if (errmaj) 771 *errmaj = LDR_NOMEM; 772 goto LoadModule_fail; 773 } 774 initdata = LoaderSymbolFromModule(ret->handle, p); 775 if (initdata) { 776 ModuleSetupProc setup; 777 ModuleTearDownProc teardown; 778 XF86ModuleVersionInfo *vers; 779 780 vers = initdata->vers; 781 setup = initdata->setup; 782 teardown = initdata->teardown; 783 784 if (vers) { 785 if (!CheckVersion(module, vers, modreq)) { 786 if (errmaj) 787 *errmaj = LDR_MISMATCH; 788 goto LoadModule_fail; 789 } 790 } 791 else { 792 LogMessage(X_ERROR, "LoadModule: Module %s does not supply" 793 " version information\n", module); 794 if (errmaj) 795 *errmaj = LDR_INVALID; 796 goto LoadModule_fail; 797 } 798 if (setup) 799 ret->SetupProc = setup; 800 if (teardown) 801 ret->TearDownProc = teardown; 802 ret->VersionInfo = vers; 803 } 804 else { 805 /* no initdata, fail the load */ 806 LogMessage(X_ERROR, "LoadModule: Module %s does not have a %s " 807 "data object.\n", module, p); 808 if (errmaj) 809 *errmaj = LDR_INVALID; 810 goto LoadModule_fail; 811 } 812 if (ret->SetupProc) { 813 ret->TearDownData = ret->SetupProc(ret, options, errmaj, NULL); 814 if (!ret->TearDownData) { 815 goto LoadModule_fail; 816 } 817 } 818 else if (options) { 819 LogMessage(X_WARNING, "Module Options present, but no SetupProc " 820 "available for %s\n", module); 821 } 822 goto LoadModule_exit; 823 824 LoadModule_fail: 825 UnloadModule(ret); 826 ret = NULL; 827 828 LoadModule_exit: 829 FreePatterns(patterns); 830 free(found); 831 free(name); 832 free(p); 833 834 return ret; 835} 836 837void 838UnloadModule(void *_mod) 839{ 840 ModuleDescPtr mod = _mod; 841 842 if (mod == (ModuleDescPtr) 1) 843 return; 844 845 if (mod == NULL) 846 return; 847 848 if (mod->VersionInfo) { 849 const char *name = mod->VersionInfo->modname; 850 851 if (mod->parent) 852 LogMessageVerbSigSafe(X_INFO, 3, "UnloadSubModule: \"%s\"\n", name); 853 else 854 LogMessageVerbSigSafe(X_INFO, 3, "UnloadModule: \"%s\"\n", name); 855 856 if (mod->TearDownData != ModuleDuplicated) { 857 if ((mod->TearDownProc) && (mod->TearDownData)) 858 mod->TearDownProc(mod->TearDownData); 859 LoaderUnload(name, mod->handle); 860 } 861 } 862 863 if (mod->child) 864 UnloadModule(mod->child); 865 if (mod->sib) 866 UnloadModule(mod->sib); 867 free(mod); 868} 869 870void 871UnloadSubModule(void *_mod) 872{ 873 ModuleDescPtr mod = (ModuleDescPtr) _mod; 874 875 /* Some drivers are calling us on built-in submodules, ignore them */ 876 if (mod == (ModuleDescPtr) 1) 877 return; 878 RemoveChild(mod); 879 UnloadModule(mod); 880} 881 882static void 883RemoveChild(ModuleDescPtr child) 884{ 885 ModuleDescPtr mdp; 886 ModuleDescPtr prevsib; 887 ModuleDescPtr parent; 888 889 if (!child->parent) 890 return; 891 892 parent = child->parent; 893 if (parent->child == child) { 894 parent->child = child->sib; 895 return; 896 } 897 898 prevsib = parent->child; 899 mdp = prevsib->sib; 900 while (mdp && mdp != child) { 901 prevsib = mdp; 902 mdp = mdp->sib; 903 } 904 if (mdp == child) 905 prevsib->sib = child->sib; 906 child->sib = NULL; 907 return; 908} 909 910void 911LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) 912{ 913 const char *msg; 914 MessageType type = X_ERROR; 915 916 switch (errmaj) { 917 case LDR_NOERROR: 918 msg = "no error"; 919 break; 920 case LDR_NOMEM: 921 msg = "out of memory"; 922 break; 923 case LDR_NOENT: 924 msg = "module does not exist"; 925 break; 926 case LDR_NOLOAD: 927 msg = "loader failed"; 928 break; 929 case LDR_ONCEONLY: 930 msg = "already loaded"; 931 type = X_INFO; 932 break; 933 case LDR_MISMATCH: 934 msg = "module requirement mismatch"; 935 break; 936 case LDR_BADUSAGE: 937 msg = "invalid argument(s) to LoadModule()"; 938 break; 939 case LDR_INVALID: 940 msg = "invalid module"; 941 break; 942 case LDR_BADOS: 943 msg = "module doesn't support this OS"; 944 break; 945 case LDR_MODSPECIFIC: 946 msg = "module-specific error"; 947 break; 948 default: 949 msg = "unknown error"; 950 } 951 if (name) 952 LogMessage(type, "%s: Failed to load module \"%s\" (%s, %d)\n", 953 name, modname, msg, errmin); 954 else 955 LogMessage(type, "Failed to load module \"%s\" (%s, %d)\n", 956 modname, msg, errmin); 957} 958 959/* Given a module path or file name, return the module's canonical name */ 960static char * 961LoaderGetCanonicalName(const char *modname, PatternPtr patterns) 962{ 963 char *str; 964 const char *s; 965 int len; 966 PatternPtr p; 967 regmatch_t match[2]; 968 969 /* Strip off any leading path */ 970 s = strrchr(modname, '/'); 971 if (s == NULL) 972 s = modname; 973 else 974 s++; 975 976 /* Find the first regex that is matched */ 977 for (p = patterns; p->pattern; p++) 978 if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { 979 len = match[1].rm_eo - match[1].rm_so; 980 str = malloc(len + 1); 981 if (!str) 982 return NULL; 983 strncpy(str, s + match[1].rm_so, len); 984 str[len] = '\0'; 985 return str; 986 } 987 988 /* If there is no match, return the whole name minus the leading path */ 989 return strdup(s); 990} 991 992/* 993 * Return the module version information. 994 */ 995unsigned long 996LoaderGetModuleVersion(ModuleDescPtr mod) 997{ 998 if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) 999 return 0; 1000 1001 return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, 1002 mod->VersionInfo->minorversion, 1003 mod->VersionInfo->patchlevel); 1004} 1005