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 "fb", 625 "i2c", 626 "ramdac", 627 "dbe", 628 "record", 629 "extmod", 630 "dri", 631 "dri2", 632#ifdef DRI3 633 "dri3", 634#endif 635#ifdef PRESENT 636 "present", 637#endif 638 NULL 639}; 640 641/* 642 * LoadModule: load a module 643 * 644 * module The module name. Normally this is not a filename but the 645 * module's "canonical name. A full pathname is, however, 646 * also accepted. 647 * options A NULL terminated list of Options that are passed to the 648 * module's SetupProc function. 649 * modreq An optional XF86ModReqInfo* containing 650 * version/ABI/vendor-ABI requirements to check for when 651 * loading the module. The following fields of the 652 * XF86ModReqInfo struct are checked: 653 * majorversion - must match the module's majorversion exactly 654 * minorversion - the module's minorversion must be >= this 655 * patchlevel - the module's minorversion.patchlevel must be 656 * >= this. Patchlevel is ignored when 657 * minorversion is not set. 658 * abiclass - (string) must match the module's abiclass 659 * abiversion - must be consistent with the module's 660 * abiversion (major equal, minor no older) 661 * moduleclass - string must match the module's moduleclass 662 * string 663 * "don't care" values are ~0 for numbers, and NULL for strings 664 * errmaj Major error return. 665 * 666 */ 667ModuleDescPtr 668LoadModule(const char *module, void *options, const XF86ModReqInfo *modreq, 669 int *errmaj) 670{ 671 XF86ModuleData *initdata = NULL; 672 char **pathlist = NULL; 673 char *found = NULL; 674 char *name = NULL; 675 char **path_elem = NULL; 676 char *p = NULL; 677 ModuleDescPtr ret = NULL; 678 PatternPtr patterns = NULL; 679 int noncanonical = 0; 680 char *m = NULL; 681 const char **cim; 682 683 LogMessageVerb(X_INFO, 3, "LoadModule: \"%s\"", module); 684 685 patterns = InitPatterns(NULL); 686 name = LoaderGetCanonicalName(module, patterns); 687 noncanonical = (name && strcmp(module, name) != 0); 688 if (noncanonical) { 689 LogWrite(3, " (%s)\n", name); 690 LogMessageVerb(X_WARNING, 1, 691 "LoadModule: given non-canonical module name \"%s\"\n", 692 module); 693 m = name; 694 } 695 else { 696 LogWrite(3, "\n"); 697 m = (char *) module; 698 } 699 700 /* Backward compatibility, vbe and int10 are merged into int10 now */ 701 if (!strcmp(m, "vbe")) 702 m = name = strdup("int10"); 703 704 for (cim = compiled_in_modules; *cim; cim++) 705 if (!strcmp(m, *cim)) { 706 LogMessageVerb(X_INFO, 3, "Module \"%s\" already built-in\n", m); 707 ret = (ModuleDescPtr) 1; 708 goto LoadModule_exit; 709 } 710 711 if (!name) { 712 if (errmaj) 713 *errmaj = LDR_BADUSAGE; 714 goto LoadModule_fail; 715 } 716 ret = calloc(1, sizeof(ModuleDesc)); 717 if (!ret) { 718 if (errmaj) 719 *errmaj = LDR_NOMEM; 720 goto LoadModule_fail; 721 } 722 723 pathlist = defaultPathList; 724 if (!pathlist) { 725 /* This could be a malloc failure too */ 726 if (errmaj) 727 *errmaj = LDR_BADUSAGE; 728 goto LoadModule_fail; 729 } 730 731 /* 732 * if the module name is not a full pathname, we need to 733 * check the elements in the path 734 */ 735 if (PathIsAbsolute(module)) 736 found = xstrdup(module); 737 path_elem = pathlist; 738 while (!found && *path_elem != NULL) { 739 found = FindModule(m, *path_elem, patterns); 740 path_elem++; 741 /* 742 * When the module name isn't the canonical name, search for the 743 * former if no match was found for the latter. 744 */ 745 if (!*path_elem && m == name) { 746 path_elem = pathlist; 747 m = (char *) module; 748 } 749 } 750 751 /* 752 * did we find the module? 753 */ 754 if (!found) { 755 LogMessage(X_WARNING, "Warning, couldn't open module %s\n", module); 756 if (errmaj) 757 *errmaj = LDR_NOENT; 758 goto LoadModule_fail; 759 } 760 ret->handle = LoaderOpen(found, errmaj); 761 if (ret->handle == NULL) 762 goto LoadModule_fail; 763 764 /* drop any explicit suffix from the module name */ 765 p = strchr(name, '.'); 766 if (p) 767 *p = '\0'; 768 769 /* 770 * now check if the special data object <modulename>ModuleData is 771 * present. 772 */ 773 if (asprintf(&p, "%sModuleData", name) == -1) { 774 p = NULL; 775 if (errmaj) 776 *errmaj = LDR_NOMEM; 777 goto LoadModule_fail; 778 } 779 initdata = LoaderSymbolFromModule(ret, p); 780 if (initdata) { 781 ModuleSetupProc setup; 782 ModuleTearDownProc teardown; 783 XF86ModuleVersionInfo *vers; 784 785 vers = initdata->vers; 786 setup = initdata->setup; 787 teardown = initdata->teardown; 788 789 if (vers) { 790 if (!CheckVersion(module, vers, modreq)) { 791 if (errmaj) 792 *errmaj = LDR_MISMATCH; 793 goto LoadModule_fail; 794 } 795 } 796 else { 797 LogMessage(X_ERROR, "LoadModule: Module %s does not supply" 798 " version information\n", module); 799 if (errmaj) 800 *errmaj = LDR_INVALID; 801 goto LoadModule_fail; 802 } 803 if (setup) 804 ret->SetupProc = setup; 805 if (teardown) 806 ret->TearDownProc = teardown; 807 ret->VersionInfo = vers; 808 } 809 else { 810 /* no initdata, fail the load */ 811 LogMessage(X_ERROR, "LoadModule: Module %s does not have a %s " 812 "data object.\n", module, p); 813 if (errmaj) 814 *errmaj = LDR_INVALID; 815 goto LoadModule_fail; 816 } 817 if (ret->SetupProc) { 818 ret->TearDownData = ret->SetupProc(ret, options, errmaj, NULL); 819 if (!ret->TearDownData) { 820 goto LoadModule_fail; 821 } 822 } 823 else if (options) { 824 LogMessage(X_WARNING, "Module Options present, but no SetupProc " 825 "available for %s\n", module); 826 } 827 goto LoadModule_exit; 828 829 LoadModule_fail: 830 UnloadModule(ret); 831 ret = NULL; 832 833 LoadModule_exit: 834 FreePatterns(patterns); 835 free(found); 836 free(name); 837 free(p); 838 839 return ret; 840} 841 842void 843UnloadModule(void *_mod) 844{ 845 ModuleDescPtr mod = _mod; 846 847 if (mod == (ModuleDescPtr) 1) 848 return; 849 850 if (mod == NULL) 851 return; 852 853 if (mod->VersionInfo) { 854 const char *name = mod->VersionInfo->modname; 855 856 if (mod->parent) 857 LogMessageVerbSigSafe(X_INFO, 3, "UnloadSubModule: \"%s\"\n", name); 858 else 859 LogMessageVerbSigSafe(X_INFO, 3, "UnloadModule: \"%s\"\n", name); 860 861 if (mod->TearDownData != ModuleDuplicated) { 862 if ((mod->TearDownProc) && (mod->TearDownData)) 863 mod->TearDownProc(mod->TearDownData); 864 LoaderUnload(name, mod->handle); 865 } 866 } 867 868 if (mod->child) 869 UnloadModule(mod->child); 870 if (mod->sib) 871 UnloadModule(mod->sib); 872 free(mod); 873} 874 875void 876UnloadSubModule(void *_mod) 877{ 878 ModuleDescPtr mod = (ModuleDescPtr) _mod; 879 880 /* Some drivers are calling us on built-in submodules, ignore them */ 881 if (mod == (ModuleDescPtr) 1) 882 return; 883 RemoveChild(mod); 884 UnloadModule(mod); 885} 886 887static void 888RemoveChild(ModuleDescPtr child) 889{ 890 ModuleDescPtr mdp; 891 ModuleDescPtr prevsib; 892 ModuleDescPtr parent; 893 894 if (!child->parent) 895 return; 896 897 parent = child->parent; 898 if (parent->child == child) { 899 parent->child = child->sib; 900 return; 901 } 902 903 prevsib = parent->child; 904 mdp = prevsib->sib; 905 while (mdp && mdp != child) { 906 prevsib = mdp; 907 mdp = mdp->sib; 908 } 909 if (mdp == child) 910 prevsib->sib = child->sib; 911 child->sib = NULL; 912 return; 913} 914 915void 916LoaderErrorMsg(const char *name, const char *modname, int errmaj, int errmin) 917{ 918 const char *msg; 919 MessageType type = X_ERROR; 920 921 switch (errmaj) { 922 case LDR_NOERROR: 923 msg = "no error"; 924 break; 925 case LDR_NOMEM: 926 msg = "out of memory"; 927 break; 928 case LDR_NOENT: 929 msg = "module does not exist"; 930 break; 931 case LDR_NOLOAD: 932 msg = "loader failed"; 933 break; 934 case LDR_ONCEONLY: 935 msg = "already loaded"; 936 type = X_INFO; 937 break; 938 case LDR_MISMATCH: 939 msg = "module requirement mismatch"; 940 break; 941 case LDR_BADUSAGE: 942 msg = "invalid argument(s) to LoadModule()"; 943 break; 944 case LDR_INVALID: 945 msg = "invalid module"; 946 break; 947 case LDR_BADOS: 948 msg = "module doesn't support this OS"; 949 break; 950 case LDR_MODSPECIFIC: 951 msg = "module-specific error"; 952 break; 953 default: 954 msg = "unknown error"; 955 } 956 if (name) 957 LogMessage(type, "%s: Failed to load module \"%s\" (%s, %d)\n", 958 name, modname, msg, errmin); 959 else 960 LogMessage(type, "Failed to load module \"%s\" (%s, %d)\n", 961 modname, msg, errmin); 962} 963 964/* Given a module path or file name, return the module's canonical name */ 965static char * 966LoaderGetCanonicalName(const char *modname, PatternPtr patterns) 967{ 968 char *str; 969 const char *s; 970 int len; 971 PatternPtr p; 972 regmatch_t match[2]; 973 974 /* Strip off any leading path */ 975 s = strrchr(modname, '/'); 976 if (s == NULL) 977 s = modname; 978 else 979 s++; 980 981 /* Find the first regex that is matched */ 982 for (p = patterns; p->pattern; p++) 983 if (regexec(&p->rex, s, 2, match, 0) == 0 && match[1].rm_so != -1) { 984 len = match[1].rm_eo - match[1].rm_so; 985 str = malloc(len + 1); 986 if (!str) 987 return NULL; 988 strncpy(str, s + match[1].rm_so, len); 989 str[len] = '\0'; 990 return str; 991 } 992 993 /* If there is no match, return the whole name minus the leading path */ 994 return strdup(s); 995} 996 997/* 998 * Return the module version information. 999 */ 1000unsigned long 1001LoaderGetModuleVersion(ModuleDescPtr mod) 1002{ 1003 if (!mod || mod == (ModuleDescPtr) 1 || !mod->VersionInfo) 1004 return 0; 1005 1006 return MODULE_VERSION_NUMERIC(mod->VersionInfo->majorversion, 1007 mod->VersionInfo->minorversion, 1008 mod->VersionInfo->patchlevel); 1009} 1010